memory usage of Java processes
When running a Java application, the Java runtime creates an operating system process that, as an operating system process, faces the memory-addressing capabilities of the same memory-limiting schema as the rest of the process relies on the number of bits of the processor, for example, The number of bits that a 32-bit or 64-bit process can handle determines the range of memory the processor can address: 32 bits provide a 2^32 addressable range, which is 4,294,967,296 bits, or 4GB. The addressable range of the 64-bit processor increases significantly: 2^64, or 18,446,744,073,709,551,616, or exabyte (Bai byte).
The amount of memory consumed by the OS and C runs depends on the OS used, but usually in large numbers: Windows defaults to 2GB of memory. The remaining addressable space is the memory that can be used by the actual process to run.
For Java applications, user space is the memory consumed by the Java process, which actually contains two pools: the Java heap and the native (non-Java) heap. The size of the Java heap is controlled by the Java heap settings of the JVM:-xms and-xmx set the minimum and maximum Java heaps respectively. After the Java heap has been assigned to the maximum size setting, the remaining user space is the native heap. The following shows a memory layout for a 32-bit Java process
The addressable range has a total of 4gb,os and C runtimes that occupy approximately 2GB of the 1gb,java heap and occupy other parts of the machine heap. Note that the JVM itself consumes memory, just as the OS kernel and C run, while the JVM occupies a subset of the native heap.
Second, Java object memory usage
When Java code uses the new operator to create an instance of a Java object, it actually allocates more data than you think. For example, the size ratio of an int value to an integer object is 1:4. The extra overhead stems from the metadata that the JVM uses to describe Java objects. These typically include:
Class: A pointer to the class information that describes the object type. For example, for a Java.lang.Integer object, this is a pointer to the Java.lang.Integer class.
Tags: a set of tags that describe the state of an object, including the object's hash code (if any), and the shape of the object (that is, whether the object is an array).
Lock: The synchronization information of an object, that is, whether the object is currently synchronizing.
Object metadata immediately follows the object data itself, including the fields stored in the object instance. For a Java.lang.Integer object, this is an int.
If you are running a 32-bit JVM, the layout of the object may be as shown when you create the Java.lang.Integer object instance
128 bits of data are used to store an int value of 32 bits, while object metadata occupies the remaining 96 bits.
three, Java array object memory usage
An array object, such as an array of int values, has a similar shape and structure to a standard Java object. The main difference is that the array object contains additional metadata that describes the size of the array.
Therefore, the metadata for the data object includes:
Class: A pointer to the class information that describes the object type. For example, for an int field array, this is a pointer to the int[] class.
Tags: a set of tags that describe the state of an object, including the object's hash code (if any), and the shape of the object (that is, whether the object is an array).
Lock: The synchronization information of an object, that is, whether the object is currently synchronizing.
Size: The size of the array.
Example of layout for an int array object
160 bits of data are used to store 32-bit data within an int value, while the array metadata occupies the remaining 160 bits.
Four, compare 32-bit and 64-bit Java Object Memory usage
The 64-bit processor has a much higher memory addressable capacity than the 32-bit processor. For a 64-bit process, the size of some data fields in the Java object (especially object metadata) also needs to be increased to 64 bits. The size of other data field types, such as int, Byte, and long, does not change.
An example of the layout of a 64-bit process Java.lang.Integer object and an int array
For a 64-bit Integer object, 224 bits of data are now used to store 32 bits of the int field, with a cost ratio of 7:1. For a 64-bit cell int array, 288 bits of data are used to store 32-bit int entries, with a cost ratio of 9:1. Applications running in the 32-bit Java runtime can significantly increase their Java heap memory usage when migrating to a 64-bit Java runtime. Typically, the increase is about 70% of the original heap size.
, a Java application that uses the 1GB Java heap in a 32-bit Java runtime typically needs to use a 1.7GB Java heap after migrating to a 64-bit Java runtime. Note that this memory increase is not limited to the Java heap. The use of the native heap memory area will also increase, and sometimes even increase by more than 90%.
memory usage of Java collections
Large amounts of data are stored and managed using the standard Java collections classes provided by the core Java APIs. It is important to understand the functionality provided by each collection and the associated memory overhead. Overall, the higher the level of collection functionality, the higher the memory overhead,
Some of the most commonly used collections are as follows:
HashSet
HashMap
Hashtable
LinkedList
ArrayList
(HashSet is a wrapper around a HashMap object that offers less functionality than HashMap and a slightly smaller capacity.) )
Attribute rollup, memory overhead
Collection |
Performance |
Default Capacity |
space-Time size |
Cost of 10K entries |
set the size exactly. |
Extended Algorithm |
HashSet |
O (1) |
16 |
144 |
360K |
Whether |
X2 |
HashMap |
O (1) |
16 |
128 |
360K |
Whether |
X2 |
Hashtable |
O (1) |
11 |
104 |
360K |
Whether |
X2+1 |
LinkedList |
O (N) |
1 |
48 |
240K |
Is |
+1 |
ArrayList |
O (N) |
10 |
88 |
40K |
Whether |
x1.5 |
StringBuffer |
O (1) |
16 |
72 |
24 |
Whether |
X2 |
The performance of a Hash set is higher than that of any List, but the cost of each goal is higher. For smaller collections that are less focused on access performance, the List is a reasonable choice. The performance of the ArrayList and LinkedList collections is roughly the same, but its memory footprint is quite different: ArrayList is much smaller than linkedlist per item size, but it is not exactly sized. The correct implementation of the list to use is ArrayList or LinkedList depending on the predictability of the list length. If the length is unknown, the correct choice may be linkedlist, because the collection contains less space. If the size is known, the ArrayList memory overhead is lower.
Vi. ArrayList and HashMap capacity growth patterns
(1) The way of ArrayList capacity growth
Public boolean Add (E e) {
ensurecapacity (size + 1);//capacity growth
elementdata[size++] = E;
return true;
Public
void ensurecapacity (int mincapacity) {
modcount++;
int ldcapacity = elementdata.length;
if (Mincapacity > Oldcapacity) {
Object olddata[] = elementdata;
int newcapacity = (oldcapacity * 3)/2 + 1;
if (Newcapacity < mincapacity) {
newcapacity = mincapacity;
}
Elementdata = arrays.copyof (Elementdata, newcapacity); Copy in turn
}
int newcapacity = (oldcapacity * 3)/2 + 1; That is 1.5 times times the original capacity of +1. Then copy the original data through the underlying copy method.
If the amount of data is large, the number of times that the array is redistributed will increase, but for the normal amount of data,
1000 need to be assigned 11 times
10,001 level needs to be allocated 17 times
100,000 need to be assigned 23 times
1 million need to be assigned 28 times
Therefore, according to the actual situation, it is necessary to roughly allocate an initial capacity. But if your initial capacity is too large and the data is growing slowly, it is wasting memory.
How to choose, or to see the specific application of the scene.
(2), HashMap capacity growth mode
HashMap mainly use arrays to store data, we all know that it will hash the key, the HA operation will have a duplicate hash value, for the hash value of the conflict, HashMap using the linked list to solve.
Transient entry[] table;
Entry is the class that the HashMap uses to store data, which has the following attributes
Final K Key;
V value;
final int hash;
Entry<k,v> Next; Next is the existence of a hash conflict.
When you put an element in, if you reach the capacity limit, HashMap will expand, the new capacity is always twice times the original.
if (size++ >= threshold) {
Resize (2 * table.length);
}
When the value specified by threshold is reached, the expansion is started, threshold= the maximum capacity * load factor.
If the data size is fixed, it is best to set a reasonable capacity value for HashMap
According to the analysis above, the initial default capacity of HashMap is 16, the default load factor is 0.75, that is, if the default constructor of HashMap is used, when the data is increased, the actual capacity of the data exceeds 16*0.75=12, and the HashMap expands, the expansion brings a series of operations , the new one is twice times the original size of the array, all the original elements of the hash, if your data has thousands of tens of thousands of, and the default HashMap constructor, the result is very tragic, because HashMap constantly expanding, constantly hashing, in the use of HashMap scene, Not many threads share a hashmap, and unless packaged and synchronized with HashMap, the resulting memory overhead and CPU overhead can be fatal in some cases.