茫茫網海中的冷日
         
茫茫網海中的冷日
發生過的事,不可能遺忘,只是想不起來而已!
 恭喜您是本站第 1671874 位訪客!  登入  | 註冊
主選單

Google 自訂搜尋

Goole 廣告

隨機相片
IMG_DPP_0005.jpg

授權條款

使用者登入
使用者名稱:

密碼:


忘了密碼?

現在就註冊!

爪哇咖啡屋 : [轉貼]Guide to the Most Important JVM Parameters

發表者 討論內容
冷日
(冷日)
Webmaster
  • 註冊日: 2008/2/19
  • 來自:
  • 發表數: 15771
[轉貼]Guide to the Most Important JVM Parameters

Guide to the Most Important JVM Parameters

Last modified: June 1, 2019

1. Overview

In this quick tutorial, we’ll explore the most well-known options which can be used to configure the Java Virtual Machine.

2. Explicit Heap Memory – Xms and Xmx Options

One of the most common performance-related practices is to initialize the heap memory as per the application requirements.

That’s why we should specify minimal and maximal heap size. Below parameters can be used for achieving it:


-Xms<heap size>[unit]
-Xmx<heap size>[unit]

Here, unit denotes the unit in which the memory (indicated by heap size) is to be initialized. Units can be marked as ‘g’ for GB, ‘m’ for MB and ‘k’ for KB.

For example, if we want to assign minimum 2 GB and maximum 5 GB to JVM, we need to write:

-Xms2G -Xmx5G

Starting with Java 8, the size of Metaspace is not defined. Once it reaches the global limit, JVM automatically increases it, However, to overcome any unnecessary instability, we can set Metaspace size with:

-XX:MaxMetaspaceSize=<metaspace size>[unit]

Here, metaspace size denotes the amount of memory we want to assign to Metaspace.

As per
Oracle guidelines, after total available memory, the second most influential factor is the proportion of the heap reserved for the Young Generation. By default, the minimum size of the YG is 1310 MB, and maximum size is unlimited.

We can assign them explicitly:


-XX:NewSize=<young size>[unit]
-XX:MaxNewSize=<young size>[unit]

3. Garbage Collection


For better stability of the application, choosing of right Garbage Collection algorithm is critical.

JVM has four types of GC implementations:

  • Serial Garbage Collector
  • Parallel Garbage Collector
  • CMS Garbage Collector
  • G1 Garbage Collector

These implementations can be declared with the below parameters:


-XX:+UseSerialGC
-XX:+UseParallelGC
-XX:+USeParNewGC
-XX:+UseG1GC

More details on Garbage Collection implementations can be found here.

4. GC Logging

To strictly monitor the application health, we should always check the JVM’s Garbage Collection performance. The easiest way to do this is to log the GC activity in human readable format.

Using the following parameters, we can log the GC activity:


-XX:+UseGCLogFileRotation
-XX:NumberOfGCLogFiles=< number of log files >
-XX:GCLogFileSize=< file size >[ unit ]
-Xloggc:/path/to/gc.log

UseGCLogFileRotation specifies the log file rolling policy, much like log4j, s4lj, etc. NumberOfGCLogFiles denotes the max number of log files that can be written for a single application life cycle. GCLogFileSize specifies the max size of the file. Finally, loggc denotes its location.

Point to note here is that, there are two more JVM parameters available ( -XX:+PrintGCTimeStamps and -XX:+PrintGCDateStamps) which can be used to print date-wise timestamp in the GC log.

For example, if we want to assign a maximum of 100 GC log files, each having a maximum size of 50 MB and want to store them in ‘ /home/user/log/’location, we can use below syntax:


-XX:+UseGCLogFileRotation
-XX:NumberOfGCLogFiles=10
-XX:GCLogFileSize=50M
-Xloggc:/home/user/log/gc.log

However, the problem is that one additional daemon thread is always used for monitoring system time in the background. This behavior may create some performance bottleneck; that’s why it’s always better not to play with this parameter in production.

5. Handling Out of Memory

It’s very common for a large application to face out of memory error which, in turn, results in the application crash. It’s a very critical scenario and very hard to replicate to troubleshoot the issue.

That’s why JVM comes with some parameters which dump heap memory into a physical file which can be used later for finding out leaks:


-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=./java_pid<pid>.hprof
-XX:OnOutOfMemoryError="< cmd args >;< cmd args >"
-XX:+UseGCOverheadLimit

A couple of points to note here:

  • HeapDumpOnOutOfMemoryError instructs the JVM to dump heap into physical file in case of OutOfMemoryError
  • HeapDumpPath denotes the path where the file is to be written; any filename can be given; however, if JVM finds a <pid> tag in the name, the process id of the current process causing the out of memory error will be appended to the file name with .hprof format
  • OnOutOfMemoryError is used to issue emergency commands to be executed in case of out of memory error; proper command should be used in the space of cmd args. For example, if we want to restart the server as soon as out of memory occur, we can set the parameter:
-XX:OnOutOfMemoryError="shutdown -r"
  • UseGCOverheadLimit
    is a policy that limits the proportion of the VM’s time that is spent in GC before an OutOfMemory error is thrown

6. 32/64 Bit

In the OS environment where both 32 and 64-bit packages are installed, the JVM automatically chooses 32-bit environmental packages.

If we want to set the environment to 64 bit manually, we can do so using below parameter:

-d<OS bit>

OS bit can be either 32 or 64. More information about this can be found here.

7. Misc

  • -server: enables “Server Hotspot VM”; this parameter is used by default in 64 bit JVM
  • -XX:+UseStringDeduplication: Java 8u20
    has introduced this JVM parameter for reducing the unnecessary use of memory by creating too many instances of the same String; this optimizes the heap memory by reducing duplicate String values to a single global char[] array
  • -XX:+UseLWPSynchronization: sets LWP ( Light Weight Process) – based synchronization policy instead of thread-based synchronization
  • -XX:LargePageSizeInBytes: sets the large page size used for the Java heap; it takes the argument in GB/MB/KB; with larger page sizes we can make better use of virtual memory hardware resources; however, this may cause larger space sizes for the PermGen, which in turn can force to reduce the size of Java heap space
  • -XX:MaxHeapFreeRatio: sets the maximum percentage of heap free after GC to avoid shrinking.
  • -XX:MinHeapFreeRatio
    : sets the minimum percentage of heap free after GC to avoid expansion; to monitor the heap usage you can use VisualVM shipped with JDK.
  • -XX:SurvivorRatio: Ratio of eden/ survivor space size – for example, -XX:SurvivorRatio=6 sets the ratio between each survivor space and eden space to be 1:6,
  • -XX:+UseLargePages: use large page memory if it is supported by the system; please note that OpenJDK 7 tends to crash if using this JVM parameter
  • -XX:+UseStringCache: enables caching of commonly allocated strings available in the String pool
  • -XX:+UseCompressedStrings: use a byte[] type for String objects which can be represented in pure ASCII format

  • -XX:+OptimizeStringConcat:
    it optimizes String concatenation operations where possible

8. Conclusion

In this quick article, we learned about some important JVM parameters – which can be used to tune and improve general application performance.

Some of these can also be used for debugging purposes.

If you want to explore the reference parameters in more detail, you can get started here.


原文出處:Guide to the Most Important JVM Parameters | Baeldung
冷日
(冷日)
Webmaster
  • 註冊日: 2008/2/19
  • 來自:
  • 發表數: 15771
[轉貼]Java Memory Management

Java Memory Management

This deep dive into Java memory management will enhance your knowledge of how the heap works, reference types, and garbage collection.

Join the DZone community and get the full member experience.

Join For Free

You might think that if you are programming in Java, what do you need to know about how memory works? Java has automatic memory management, a nice and quiet garbage collector that works in the background to clean up the unused objects and free up some memory.


Therefore, you as a Java programmer do not need to bother yourself with problems like destroying objects, as they are not used anymore. However, even if this process is automatic in Java, it does not guarantee anything. By not knowing how the garbage collector and Java memory is designed, you could have objects that are not eligible for garbage collecting, even if you are no longer using them.

So knowing how memory actually works in Java is important, as it gives you the advantage of writing high-performance and optimized applications that will never ever crash with an OutOfMemoryError . On the other hand, when you find yourself in a bad situation, you will be able  to quickly find the memory leak.

To start with, let’s have a look at how the memory is generally organized in Java:

Memory Structure

Generally, memory is divided into two big parts: the stack and the heap. Please keep in mind that the size of memory types in this picture are not proportional to the memory size in reality. The heap is a huge amount of memory compared to the stack.

The Stack

Stack memory is responsible for holding references to heap objects and for storing value types (also known in Java as primitive types), which hold the value itself rather than a reference to an object from the heap.


In addition, variables on the stack have a certain visibility, also called scope. Only objects from the active scope are used. For example, assuming that we do not have any global scope variables (fields), and only local variables, if the compiler executes a method’s body, it can access only objects from the stack that are within the method’s body. It cannot access other local variables, as those are out of scope. Once the method completes and returns, the top of the stack pops out, and the active scope changes.

Maybe you noticed that in the picture above, there are multiple stack memories displayed. This due to the fact that the stack memory in Java is allocated per Thread. Therefore, each time a Thread is created and started, it has its own stack memory — and cannot access another thread’s stack memory.

The Heap


This part of memory stores the actual object in memory. Those are referenced by the variables from the stack. For example, let’s analyze what happens in the following line of code:

StringBuilder builder = new StringBuilder();


The  new keyword is responsible for ensuring that there is enough free space on heap, creating an object of the StringBuilder type in memory and referring to it via the “builder” reference, which goes on the stack.

There exists only one heap memory for each running JVM process. Therefore, this is a shared part of memory regardless of how many threads are running. Actually, the heap structure is a bit different than it is shown in the picture above. The heap itself is divided into a few parts, which facilitates the process of garbage collection.


The maximum stack and the heap sizes are not predefined — this depends on the running machine. However, later in this article, we will look into some JVM configurations that will allow us to specify their size explicitly for a running application.

Reference Types

If you look closely at the Memory Structure picture, you will probably notice that the arrows representing the references to the objects from the heap are actually of different types. That is because, in the Java programming language, we have different types of references: strong, weak, soft, and phantom references. The difference between the types of references is that the objects on the heap they refer to are eligible for garbage collecting under the different criteria. Let’s have a closer look at each of them.

1. Strong Reference


These are the most popular reference types that we all are used to. In the example above with the StringBuilder, we actually hold a strong reference to an object from the heap. The object on the heap it is not garbage collected while there is a strong reference pointing to it, or if it is strongly reachable through a chain of strong references.

2. Weak Reference

In simple terms, a weak reference to an object from the heap is most likely to not survive after the next garbage collection process. A weak reference is created as follows:

WeakReference<StringBuilder> reference = new WeakReference<>(new StringBuilder());



A nice use case for weak references are caching scenarios. Imagine that you retrieve some data, and you want it to be stored in memory as well — the same data could be requested again. On the other hand, you are not sure when, or if, this data will be requested again. So you can keep a weak reference to it, and in case the garbage collector runs, it could be that it destroys your object on the heap. Therefore, after a while, if you want to retrieve the object you refer to, you might suddenly get back a  null value. A nice implementation for caching scenarios is the collection WeakHashMap<K,V>. If we open the WeakHashMap class in the Java API, we see that its entries actually extend the  WeakReference class and uses its ref field as the map’s key:


/**
* The entries in this hash table extend WeakReference, using its main ref
* field as the key.
*/
private static class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V> {
V value;


Once a key from the WeakHashMap is garbage collected, the entire entry is removed from the map.

3. Soft Reference

These types of references are used for more memory-sensitive scenarios, since those are going to be garbage collected only when your application is running low on memory. Therefore, as long as there is no critical need to free up some space, the garbage collector will not touch softly reachable objects. Java guarantees that all soft referenced objects are cleaned up before it throws an OutOfMemoryError . The Javadocs state, “all soft references to softly-reachable objects are guaranteed to have been cleared before the virtual machine throws an OutOfMemoryError.”

Similar to weak references, a soft reference is created as follows:

SoftReference<StringBuilder> reference = new SoftReference<>(new StringBuilder());



4. Phantom Reference

Used to schedule post-mortem cleanup actions, since we know for sure that objects are no longer alive. Used only with a reference queue, since the .get() method of such references will always return null . These types of references are considered preferable to finalizers.

How Strings Are Referenced

The  String type in Java is a bit differently treated. Strings are immutable, meaning that each time you do something with a string, another object is actually created on the heap. For strings, Java manages a string pool in memory. This means that Java stores and reuse strings whenever possible. This is mostly true for string literals. For example:


String localPrefix = "297"; //1
String prefix = "297"; //2
if (prefix == localPrefix)
{
System.out.println("Strings are equal" );
}
else
{
System.out.println("Strings are different");
}


When running, this prints out the following:

Strings are equal

Therefore, it turns out that after comparing the two references of the String type, those actually point to the same objects on the heap. However, this is not valid for Strings that are computed. Let’s assume that we have the following change in line //1 of the above code

String localPrefix = new Integer(297).toString(); //1


Output:

Strings are different

In this case, we actually see that we have two different objects on the heap. If we consider that the computed String will be used quite often, we can force the JVM to add it to the string pool by adding the .intern() method at the end of computed string:

String localPrefix = new Integer(297).toString().intern(); //1



Adding the above change creates the following output:

Strings are equal

Garbage Collection Process

As discussed earlier, depending on the type of reference that a variable from the stack holds to an object from the heap, at a certain point in time, that object becomes eligible for the garbage collector.

Garbage-eligible objects

For example, all objects that are in red are eligible to be collected by the garbage collector. You might notice that there is an object on the heap, which has strong references to other objects that are also on the heap (e.g. could be a list that has references to its items, or an object that has two referenced type fields). However, since the reference from the stack is lost, it cannot be accessed anymore, so it is garbage as well.


To go a bit deeper into the details, let’s mention a few things first:

  • This process is triggered automatically by Java, and it is up to Java when and whether or not to start this process.

  • It is actually an expensive process. When the garbage collector runs, all threads in your application are paused (depending on the GC type, which will be discussed later).

  • This is actually a more complicated process than just garbage collecting and freeing up memory.

Even though Java decides when to run the garbage collector, you may explicitly call System.gc() and expect that the garbage collector will run when executing this line of code, right?

This is a wrong assumption.

You only kind of ask Java to run the garbage collector, but it’s, again, up to it whether or not to do that. Anyway, explicitly calling  System.gc() is not advised.


Since this is a quite complex process, and it might affect you performance, it is implemented in a smart way. A so-called “Mark and Sweep” process is used for that. Java analyzes the variables from the stack and “marks” all the objects that need to be kept alive. Then, all the unused objects are cleaned up.

So actually, Java does not collect any garbage. In fact, the more garbage there is, and the fewer that objects are marked alive, the faster the process is. To make this even more optimized, heap memory actually consists of multiple parts. We can visualize the memory usage and other useful things with JVisualVM, a tool that comes with the Java JDK. The only thing you have to do is install a plugin named Visual GC, which allows you to see how the memory is actually structured. Let’s zoom in a bit and break down the big picture:

Heap memory generations


When an object is created, it is allocated on the Eden(1) space. Because the Eden space is not that big, it gets full quite fast. The garbage collector runs on the Eden space and marks objects as alive.

Once an object survives a garbage collecting process, it gets moved into a so-called survivor space S0(2). The second time the garbage collector runs on the Eden space, it moves all surviving objects into the S1(3) space. Also, everything that is currently on S0(2) is moved into the S1(3) space.

If an object survives for X rounds of garbage collection (X depends on the JVM implementation, in my case it’s 8), it is most likely that it will survive forever, and it gets moved into the Old(4) space.


Taking everything said so far, if you look at the garbage collector graph(6), each time it has run, you can see that the objects switch to the survivor space and that the Eden space gained space. And so on and so forth. The old generation can be also garbage collected, but since it is a bigger part of the memory compared to Eden space, it does not happen that often. The Metaspace(5) is used to store the metadata about your loaded classes in the JVM.

The presented picture is actually a Java 8 application. Prior to Java 8, the structure of the memory was a bit different. The metaspace is called actually the PermGen. space. For example, in Java 6, this space also stored the memory for the string pool. Therefore, if you have too many strings in your Java 6 application, it might crash.

Garbage Collector Types


Actually, the JVM has three types of garbage collectors, and the programmer can choose which one should be used. By default, Java chooses the garbage collector type to be used based on the underlying hardware.

1. Serial GC – A single thread collector. Mostly applies to small applications with small data usage. Can be enabled by specifying the command line option: -XX:+UseSerialGC

2. Parallel GC – Even from the naming, the difference between Serial and Parallel would be that Parallel GC uses multiple threads to perform the garbage collecting process. This GC type is also known as the throughput collector. It can be enabled by explicitly specifying the option: -XX:+UseParallelGC


3. Mostly concurrent GC – If you remember, earlier in this article, it was mentioned that the garbage collecting process is actually pretty expensive, and when it runs, all thread are paused. However, we have this mostly concurrent GC type, which states that it works concurrent to the application. However, there is a reason why it is “mostly” concurrent. It does not work 100% concurrently to the application. There is a period of time for which the threads are paused. Still, the pause is kept as short as possible to achieve the best GC performance. Actually, there are 2 types of mostly concurrent GCs:

3.1 Garbage First – high throughput with a reasonable application pause time. Enabled with the option: -XX:+UseG1GC

3.2 Concurrent Mark Sweep – The application pause time is kept to a minimum. It can be used by specifying the option: -XX:+UseConcMarkSweepGC
. As of JDK 9, this GC type is deprecated.

Tips and Tricks

  • To minimize the memory footprint, limit the scope of the variables as much as possible. Remember that each time the top scope from the stack is popped up, the references from that scope are lost, and this could make objects eligible for garbage collecting.

  • Explicitly refer to null obsolete references. That will make objects those refer to eligible for garbage collecting.

  • Avoid finalizers. They slow down the process and they do not guarantee anything. Prefer phantom references for cleanup work.

  • Do not use strong references where weak or soft references apply. The most common memory pitfalls are caching scenarios,when data is held in memory even if it might not be needed.


  • JVisualVM also has the functionality to make a heap dump at a certain point, so you could analyze, per class, how much memory it occupies.

  • Configure your JVM based on your application requirements. Explicitly specify the heap size for the JVM when running the application. The memory allocation process is also expensive, so allocate a reasonable initial and maximum amount of memory for the heap. If you know it will not make sense to start with a small initial heap size from the beginning, the JVM will extend this memory space. Specifying the memory options with the following options:

    • Initial heap size -Xms512m – set the initial heap size to 512 megabytes.

    • Maximum heap size -Xmx1024m – set the maximum heap size to 1024 megabytes.

    • Thread stack size -Xss128m
      – set the thread stack size to 128 megabytes.

    • Young generation size -Xmn256m – set the young generation size to 256 megabytes.

  • If a Java application crashes with an  OutOfMemoryError and you need some extra info to detect the leak, run the process with the  –XX:HeapDumpOnOutOfMemory parameter, which will create a heap dump file when this error happens next time.

  • Use the  -verbose:gc option to get the garbage collection output. Each time a garbage collection takes place, an output will be generated.

Conclusion


Knowing how memory is organized gives you the advantage of writing good and optimized code in terms of memory resources. In advantage, you can tune up your running JVM, by providing different configurations that are the most suitable for your running application. Spotting and fixing memory leaks is just an easy thing to do, if using the right tools.


原文出處:Java Memory Management - DZone Java
前一個主題 | 下一個主題 | 頁首 | | |



Powered by XOOPS 2.0 © 2001-2008 The XOOPS Project|