diff --git a/config/java_memory_assistant.yml b/config/java_memory_assistant.yml index 2f94cf408a..9f4c874933 100644 --- a/config/java_memory_assistant.yml +++ b/config/java_memory_assistant.yml @@ -30,6 +30,11 @@ agent: eden: survivor: old_gen: ">600MB" + tenured_gen: + code_heap.non_nmethods: + code_heap.non_profiled_nmethods: + code_heap.profiled_nmethods: + clean_up: version: 0.+ repository_root: https://raw.githubusercontent.com/SAP/java-memory-assistant-tools/repository-cu diff --git a/docs/framework-java_memory_assistant.md b/docs/framework-java_memory_assistant.md index 6612aab909..f8a2f60594 100644 --- a/docs/framework-java_memory_assistant.md +++ b/docs/framework-java_memory_assistant.md @@ -46,6 +46,13 @@ The timestamp pattern `%ts:yyyyMMdd'T'mmssSSSZ%` is equivalent to the `%FT%T%z` | Eden | `eden` | | Survivor | `survivor` | | Old Generation | `old_gen` | +| Tenured Gen | `tenured_gen` | +| CodeHeap 'non-nmethods' | `code_heap.non_nmethods` | +| CodeHeap 'profiled nmethods' | `code_heap.profiled_nmethods` | +| CodeHeap 'non-profiled nmethods' | `code_heap.non_profiled_nmethods` | + +Different builds and versions of Java Virtual Machines offer different memory areas. +The list of supported Java Virtual Machines and the respective memory areas can be found in the [Java Memory Assistant documentation](https://github.com/SAP/java-memory-assistant#supported-jvms). The default values can be found in the [`config/java_memory_assistant.yml`][] file. diff --git a/lib/java_buildpack/framework/java_memory_assistant/agent.rb b/lib/java_buildpack/framework/java_memory_assistant/agent.rb index 89054fc542..bd0a14fbdd 100644 --- a/lib/java_buildpack/framework/java_memory_assistant/agent.rb +++ b/lib/java_buildpack/framework/java_memory_assistant/agent.rb @@ -42,13 +42,24 @@ def release .add_system_property('jma.heap_dump_name', %("#{name_pattern}")) .add_system_property 'jma.log_level', normalized_log_level + if @droplet.java_home.java_9_or_later? + # Enable access to com.sun.management.HotSpotDiagnosticMXBean to circumvent + # Java modules limitations in Java 9+ + # See https://github.com/SAP/java-memory-assistant#running-the-java-memory-assistant-on-java-11 + @droplet.java_opts + .add_preformatted_options('--add-opens jdk.management/com.sun.management.internal=ALL-UNNAMED') + end + add_system_prop_if_config_present 'check_interval', 'jma.check_interval' - add_system_prop_if_config_present 'max_frequency', 'jma.max_frequency' + + if @configuration.key?('max_frequency') + @droplet.java_opts.add_preformatted_options "'-Djma.max_frequency=#{@configuration['max_frequency']}'" + end return unless @configuration.key?('thresholds') @configuration['thresholds'].each do |key, value| - @droplet.java_opts.add_system_property "jma.thresholds.#{key}", value.to_s + @droplet.java_opts.add_preformatted_options "'-Djma.thresholds.#{key}=#{value.to_s}'" end end diff --git a/spec/java_buildpack/framework/java_memory_assistant/agent_spec.rb b/spec/java_buildpack/framework/java_memory_assistant/agent_spec.rb index 84564840ea..30161eec10 100644 --- a/spec/java_buildpack/framework/java_memory_assistant/agent_spec.rb +++ b/spec/java_buildpack/framework/java_memory_assistant/agent_spec.rb @@ -52,15 +52,54 @@ it 'updates JAVA_OPTS with default values' do component.release + expect(java_opts).not_to include('--add-opens jdk.management/com.sun.management.internal=ALL-UNNAMED') + expect(java_opts).to include('-javaagent:$PWD/.java-buildpack/java_memory_assistant_agent/' \ 'java-memory-assistant-1.2.3.jar') expect(java_opts).to include('-Djma.enabled=true') expect(java_opts).to include('-Djma.check_interval=5s') - expect(java_opts).to include('-Djma.max_frequency=1/1m') + expect(java_opts).to include('\'-Djma.max_frequency=1/1m\'') + + expect(java_opts).to include('\'-Djma.thresholds.heap=90\'') + expect(java_opts).to include('\'-Djma.thresholds.old_gen=90\'') + + end + + context do + + let(:java_home_delegate) do + delegate = JavaBuildpack::Component::MutableJavaHome.new + delegate.root = app_dir + '.test-java-home' + delegate.version = JavaBuildpack::Util::TokenizedVersion.new('1.8.0_55') + + delegate + end + + it 'it does not add the --add-opens on Java 8' do + component.release + + expect(java_opts).not_to include('--add-opens jdk.management/com.sun.management.internal=ALL-UNNAMED') + end - expect(java_opts).to include('-Djma.thresholds.heap=90') - expect(java_opts).to include('-Djma.thresholds.old_gen=90') + end + + context do + + let(:java_home_delegate) do + delegate = JavaBuildpack::Component::MutableJavaHome.new + delegate.root = app_dir + '.test-java-home' + delegate.version = JavaBuildpack::Util::TokenizedVersion.new('9.0.1') + + delegate + end + + it 'adds the --add-opens on Java 11' do + component.release + + expect(java_opts).to include('--add-opens jdk.management/com.sun.management.internal=ALL-UNNAMED') + end + end end @@ -93,15 +132,15 @@ 'java-memory-assistant-0.1.0.jar') expect(java_opts).to include('-Djma.enabled=true') expect(java_opts).to include('-Djma.check_interval=10m') - expect(java_opts).to include('-Djma.max_frequency=4/10h') + expect(java_opts).to include('\'-Djma.max_frequency=4/10h\'') expect(java_opts).to include('-Djma.log_level=DEBUG') - expect(java_opts).to include('-Djma.thresholds.heap=60') - expect(java_opts).to include('-Djma.thresholds.code_cache=30') - expect(java_opts).to include('-Djma.thresholds.metaspace=5') - expect(java_opts).to include('-Djma.thresholds.perm_gen=45.5') - expect(java_opts).to include('-Djma.thresholds.eden=90') - expect(java_opts).to include('-Djma.thresholds.survivor=95.5') - expect(java_opts).to include('-Djma.thresholds.old_gen=30') + expect(java_opts).to include('\'-Djma.thresholds.heap=60\'') + expect(java_opts).to include('\'-Djma.thresholds.code_cache=30\'') + expect(java_opts).to include('\'-Djma.thresholds.metaspace=5\'') + expect(java_opts).to include('\'-Djma.thresholds.perm_gen=45.5\'') + expect(java_opts).to include('\'-Djma.thresholds.eden=90\'') + expect(java_opts).to include('\'-Djma.thresholds.survivor=95.5\'') + expect(java_opts).to include('\'-Djma.thresholds.old_gen=30\'') end end @@ -121,6 +160,30 @@ end + context do + let(:configuration) do + { + 'thresholds' => { + 'heap' => '>600MB', + 'eden' => '< 30MB' + } + } + end + + let(:version) { '0.1.0' } + + it 'escapses redirection characters' do + component.release + + expect(java_opts).to include('-javaagent:$PWD/.java-buildpack/java_memory_assistant_agent/' \ + 'java-memory-assistant-0.1.0.jar') + + expect(java_opts).to include('\'-Djma.thresholds.heap=>600MB\'') + expect(java_opts).to include('\'-Djma.thresholds.eden=< 30MB\'') + end + + end + context do let(:configuration) do { @@ -200,7 +263,7 @@ end it 'falls back on JBP log_level when no log_level specified via configuration', - :enable_log_file, log_level: 'WARN' do + :enable_log_file, log_level: 'WARN' do component.release expect(java_opts).to include('-Djma.log_level=WARNING')