@Override
  public HeuristicResult apply(TonyApplicationData data) {
    _LOGGER.debug("Applying TaskMemoryHeuristic");
    Map<String, Map<Integer, TonyTaskData>> taskMap = data.getTaskMap();
    Configuration conf = data.getConfiguration();

    Set<String> taskTypes = com.linkedin.tony.util.Utils.getAllJobTypes(conf);
    Severity finalSeverity = Severity.NONE;
    List<HeuristicResultDetails> details = new ArrayList<>();
    int severityScore = 0;

    for (String taskType : taskTypes) {
      int taskInstances = conf.getInt(TonyConfigurationKeys.getInstancesKey(taskType), 0);
      details.add(new HeuristicResultDetails("Number of " + taskType + " tasks", String.valueOf(taskInstances)));
      if (taskInstances == 0) {
        continue;
      }

      // get per task memory requested
      String memoryString = conf.get(TonyConfigurationKeys.getResourceKey(taskType, Constants.MEMORY),
          TonyConfigurationKeys.DEFAULT_MEMORY);
      String memoryStringMB = com.linkedin.tony.util.Utils.parseMemoryString(memoryString);
      long taskBytesRequested = Long.parseLong(memoryStringMB) * FileUtils.ONE_MB;
      details.add(new HeuristicResultDetails("Requested memory (MB) per " + taskType + " task",
          Long.toString(taskBytesRequested / FileUtils.ONE_MB)));

      // get global max memory per task
      double maxMemoryBytesUsed = TonyUtils.getMaxMetricForTaskTypeAndMetricName(taskMap, taskType,
          Constants.MAX_MEMORY_BYTES);
      if (maxMemoryBytesUsed <= 0) {
        details.add(new HeuristicResultDetails("Max memory (MB) used in any " + taskType + " task", "Unknown"));
        continue;
      }
      details.add(new HeuristicResultDetails("Max memory (MB) used in any " + taskType + " task",
          Long.toString((long) maxMemoryBytesUsed / FileUtils.ONE_MB)));

      // compare to threshold and update severity
      if (taskBytesRequested <= defaultContainerMemoryBytes
          || taskBytesRequested <= maxMemoryBytesUsed + graceMemoryHeadroomBytes) {
        // If using default container memory or within grace headroom, automatic pass
        continue;
      }
      double maxMemoryRatio = maxMemoryBytesUsed / taskBytesRequested;
      Severity taskMemorySeverity = Severity.getSeverityDescending(maxMemoryRatio, maxMemoryLimits[0],
          maxMemoryLimits[1], maxMemoryLimits[2], maxMemoryLimits[3]);
      severityScore += Utils.getHeuristicScore(taskMemorySeverity, taskInstances);
      finalSeverity = Severity.max(finalSeverity, taskMemorySeverity);
    }

    return new HeuristicResult(_heuristicConfData.getClassName(), _heuristicConfData.getHeuristicName(), finalSeverity,
        severityScore, details);
  }
Constructor for {@link TaskMemoryHeuristic}.
@param heuristicConfData  the configuration for this heuristic
app/com/linkedin/drelephant/tony/heuristics/TaskMemoryHeuristic.java