JAVA Memory Management Summary
How Java manages memory
The memory management of Java is the allocation and release of objects. (Two parts)
Allocation: The allocation of memory is done by the program, and the programmer needs to request memory space for each object through the keyword new (except for the base type), and all objects allocate space in the heap.
Release: The release of an object is determined and executed by the garbage collection mechanism, which does simplify the programmer's work. But it also adds to the JVM's work. Because, in order for the GC to properly dispose of objects, the GC must monitor the running state of each object, including the application, reference, reference, assignment, etc. of the object, which the GC needs to monitor.
What is Java's memory leak?
In Java, the memory leak is the existence of some assigned objects, which have the following two characteristics, first of all, these objects are accessible, that is, in the graph, the existence of the path can be connected to it (that is, the memory object still exists), and second, these objects are useless, that is, the program will no longer use these objects. If the object satisfies both conditions, these objects can be judged as a memory leak in Java, which is not reclaimed by the GC, but it consumes memory.
The memory area of the JVM is composed
Java has two kinds of memory: one is stack memory, the other is heap memory 1. The basic type variables and the reference variables of the objects defined in the function are allocated in the stack memory of the function; 2. When heap memory is used to hold objects and arrays created by new and the instance variables of an object define a variable in a function (code block), Java allocates memory space for the variable in the stack, and when the scope of the variable is exceeded, Java automatically frees the allocated memory space for that variable. The memory allocated in the heap is managed by the Java Virtual machine's automatic garbage collector
Advantages and disadvantages of heap and stack
The advantage of a heap is that it can dynamically allocate memory size, and the lifetime does not have to tell the compiler beforehand because it allocates memory dynamically at run time.
The disadvantage is that the memory is dynamically allocated at run time, the access speed is slow, and the advantage of the stack is that the access speed is faster than the heap, second only to the registers directly in the CPU.
In addition, the stack data can be shared. However, the disadvantage is that the size and lifetime of the data in the stack must be deterministic and inflexible.
- How data in Java is stored in memory
A) Basic data types
There are 8 basic data types in Java, namely int, short, long, byte, float, double, Boolean, char (note, and no basic type of string). The definition of this type is defined by a form such as int a = 3; long B = 255L; such as int a = 3; Here A is a reference to the int type, which points to the literal value of 3. The data of these literals, because of the size of the known, the lifetime of the known (these literals are defined in a program block, the program block exits, the field value disappears), for the sake of speed, it exists in the stack.
In addition, the stack has a very important particularity, is that there is data in the stack can be shared. For example: We also define:
int a=3;
int b = 3;
The compiler processes int a = 3 First, it creates a reference to a variable in the stack, and then looks for an address with a literal value of 3, finds an address that holds the literal value of 3, and then points A to the address of 3. then the int b = 3 is processed, and after the reference variable of B is created, B is pointed directly to the address of 3 because there are already 3 literals in the stack. In this case, A and B both point to 3. After defining the value of a and B, make a = 4, then B will not be equal to 4, or equal to 3. Inside the compiler, it will re-search the stack if there is a 4 literal value, if not, re-open the address to store the value of 4, if already, then direct a to this address. Therefore the change of a value does not affect the value of B.
B) Object
In Java, the creation of an object consists of two steps of declaring and instantiating an object, with an example to illustrate the object's memory model. Suppose there is a class rectangle defined as follows:
public class Rectangle {
Double width;
Double height;
Public Rectangle (Double w,double h) {
w = width;
h = height;
}
}
(1) memory model when declaring an object
With rectangle rect, when declaring an object rect, the memory space is allocated in the stack memory for the object's reference variable rect, but the value of rectangle is empty, which is called the rect as an empty object. An empty object cannot be used because it does not yet reference any of the entities.
(2) Memory model when object is instantiated
When executing rect=new Rectangle (3,5), two things are done: allocating memory for the class's member variable Width,height in heap memory and initializing it to the default value for each data type, followed by an explicit initialization (the initialization value at the time the class is defined), and the last call to the constructor method, Assigns a value to a member variable. Returns a reference to the object in the heap memory (the same as the first address) to the reference variable rect, which can then be referenced by a rect to the object in the heap memory.
c) Create multiple different object instances
一个类通过使用new运算符可以创建多个不同的对象实例,这些对象实例将在堆中被分配不同的内存空间,改变其中一个对象的状态不会影响其他对象的状态。例如:
Rectangle r1= New Rectangle (3,5);
Rectangle r2= New Rectangle (4,6);
At this point, the memory space is allocated for the member variable width, height of the two objects in heap memory, and the space occupied by the two objects in the heap memory is different from each other. If you have:
Rectangle r1= New Rectangle (3,5);
Rectangle R2=r1;
Only one object instance is created in heap memory, two object references are created in stack memory, and two object references point to an object instance.
d) Packing class
基本型别都有对应的包装类:如int对应Integer类,double对应Double类等,基本类型的定义都是直接在栈中,如果用包装类来创建对象,就和普通对象一样了。例如:int i=0;i直接存储在栈中。 Integer i(i此时是对象) = new Integer(5);这样,i对象数据存储在堆中,i的引用存储在栈中,通过栈中的引用来操作对象。
e) String
String is a special wrapper class data. Can be created in the following two ways: string str = new String ("abc"); string str = "ABC";
The first method of creation is the same as the creation of ordinary objects;
The second way to create it is to translate this statement into the following steps within Java:
(1) First define an object reference variable named str to the String class: String str;
(2) in the stack to find there is no value "ABC" address, if not, then open a store literal "abc"
Address, and then creates a new object o for the string class and points the string value of O to this address, and the stack
Next to this address, make a note of the referenced object o. If you already have an address with a value of "ABC", look for the object o, and
Address of the return O.
(3) Point Str to the address of the object o.
It is important to note that the string values in the generic string class are directly stored values. But like string str = "ABC";
, the string value holds a reference to the data in the existing stack.
To better illustrate this problem, we can verify it by following several code.
String str1= "ABC";
String str2= "ABC";
System.out.println (S1==S2);//true
Note that the Str1.equals (STR2) is not used here, as this will compare the values of two strings for equality. = = number, as described in the JDK, returns true only if two references point to the same object. And what we're looking at here is whether str1 and str2 all point to the same object.
Let's look at the following code again.
String str1= new String ("abc");
String str2= "ABC";
System.out.println (STR1==STR2);//false
Two references were created. Two objects were created. Two references point to a different two objects, respectively. The above two code shows that as long as new () is used to create the object, it is created in the heap, and its string is stored separately, even if the data in the stack is the same, it is not shared with the data in the stack.
f) Array
当定义一个数组,int x[];或int []x;时,在栈内存中创建一个数组引用,通过该引用(即数组名)来引用数组。x=new int[3];将在堆内存中分配3个保存int型数据的空间,堆内存的首地址放到栈内存中,每个数组元素被初始化为0。
g) Static variables
用static的修饰的变量和方法,实际上是指定了这些变量和方法在内存中的"固定位置"-static storage,可以理解为所有实例对象共有的内存空间。static变量有点类似于C中的全局变量的概念;静态表示的是内存的共享,就是它的每一个实例都指向同一个内存地址。把static拿来,就是告诉JVM它是静态的,它的引用(含间接引用)都是指向同一个位置,在那个地方,你把它改了,它就不会变成原样,你把它清理了,它就不会回来了。 那静态变量与方法是在什么时候初始化的呢?对于两种不同的类属性,static属性与instance属性,初始化的时机是不同的。instance属性在创建实例的时候初始化,static属性在类加载,也就是第一次用到这个类的时候初始化,对于后来的实例的创建,不再次进行初始化。 我们常可看到类似以下的例子来说明这个问题:
Class student{
static int numberofstudents=0;
Student ()
{
numberofstudents++;
}
}
Each time a new student instance is created, the member numberofstudents is incremented continuously, and all student instances have access to the same numberofstudents variable, in effect an int The numberofstudents variable is stored in memory only in one place.
-
Java memory Management instance
Multiple parts of a Java program (methods, variables, objects) reside in memory in the following two locations: Heap and Stack, now we only care about 3 kinds of things: instance variables, local variables and objects:
instance variables and objects residing on the heap
Local variables reside on the stack
Let's look at a Java program and see how his parts are created and mapped to stacks and heaps:
public class Dog {
Collar C;
String name; The
//1. Main () method is on the stack
public static void Main (string[] args) {
//2. Creates a reference variable D on the stack, but the dog object does not already exist
Dog D;
//3. Create a new dog object and assign it to the D reference variable
D = new Dog ();
//4. Pass a copy of the reference variable to the Go () method
D.go (d);
}
//5. Place the Go () method on the stack and use the Dog parameter as the local variable
void Go (dog) {
//6. Creates a new Collar object on the heap and assigns it to the instance variable of dog
C =new Collar ( );
}
//7. Add SetName () to the stack, and use the Dogname parameter as its local variable
void SetName (String dogname) {
//8. Name of an instance object also referencing a String object
Name=dogname;
}
//9. After the execution of the program, SetName () is completed and purged from the stack, and the local variable dogname disappears, even though the string it references is still on the heap
}
-
Garbage collection mechanism:
(Question one: What is a garbage collection mechanism?) Garbage collection is a dynamic storage management technology that automatically frees objects that are no longer referenced by the program, and implements automatic resource recovery based on a specific garbage collection algorithm. When an object is no longer referenced, the memory reclaims the space it occupies so that space is used by later new objects to avoid a memory leak. (Question two: what are the characteristics of Java garbage collection?) The Java language does not allow programmers to directly control the use of memory space. The allocation and recycling of memory space is done automatically by the JRE in the background, especially for garbage collection (Garbagecollection, also known as garbage collection), which can only be monitored and controlled by a super-thread provided by the running environment. (Question three: When will the garbage collector run?) Typically, garbage collection occurs automatically when the CPU is idle or out of space, and programmers cannot precisely control the timing and order of garbage collection. (Question four: What objects meet the garbage collection criteria?) When no gain thread can access an object, the object is eligible for garbage collection. (Question five: How does the garbage collector work?) If the garbage collector finds that an object cannot be accessed by any live thread, he will consider the object to be eligible for deletion, add it to the recycle queue, but not destroy the object immediately, and when to destroy and free memory is unpredictable. Garbage collection cannot be enforced, but Java provides methods (such as the System.GC () method) that allow you to request that the JVM perform garbage collection instead of requiring that the virtual opportunity do its best to satisfy the request, but there is no guarantee that the JVM will remove all unused objects from memory. (Question six: Can a Java program run out of memory?) Can The garbage collection system attempts to remove objects from memory when they are not being used. However, if you keep too many live objects, the system may run out of memory. The garbage collector does not guarantee enough memory to ensure that available memory is managed as efficiently as possible. (Question seven: How do I show objects that conform to the garbage collection criteria?) ) (1) null reference: When the object does not have a reachable reference to him, he is eligible for garbage collection. In other words, if there is no reference to him, deleting the object's reference can achieve the purpose, so we can set the reference variable to NULL to meet the garbage collection criteria.
StringBuffer sb = new StringBuffer ("Hello");
System.out.println (SB);
Sb=null;
(2) Re-assign a value to the reference variable: You can refer to another object by setting a reference variable to disassociate the reference variable from the reference to an object.
StringBuffer sb1 = new StringBuffer ("Hello");
StringBuffer SB2 = new StringBuffer ("Goodbye");
System.out.println (SB1);
sb1=sb2;//"Hello" at this time meets the recycling criteria
(3) object created within the method: The local variable created is only present within the duration of the method's action. Once the method returns, objects created within this method are eligible for garbage collection. One notable exception is the return object of the method.
public static void Main (string[] args) {
Date d = getDate ();
System.out.println ("D =" + D);
}
private static Date getDate () {
Date D2 = new Date ();
StringBuffer now = new StringBuffer (d2.tostring ());
System.out.println (now);
return D2;
}
(4) Quarantine reference: In this case, the object being reclaimed still has a reference, which is known as the isolated island. If there are two instances, they reference each other, and all other references to both objects are deleted, and no other thread can access either of the two objects. can also meet garbage collection conditions.
public class Island {
Island I;
public static void Main (string[] args) {
Island i2 = new Island ();
Island i3 = new Island ();
Island I4 = new Island ();
I2.i=i3;
I3.I=I4;
I4.i=i2;
I2=null;
I3=null;
I4=null;
}
}
(Issue eight: Cleanup before garbage collection--finalize () method) Java provides a mechanism that allows you to run some code before an object is just going to be garbage collected. This code is within a method named Finalize (), and all classes inherit this method from the object class. Because the garbage collector cannot be guaranteed to delete an object. Therefore, the code placed in finalize () cannot be guaranteed to run. It is therefore recommended that you do not rewrite finalize ();
7. Final question:
Final makes the modified variable "unchanged", but because the nature of the object type variable is "reference", so that the "invariant" also has two meanings: the reference itself is unchanged, and the reference point to the object does not change. The reference itself does not change:
Final StringBuffer a=new StringBuffer ("immutable");
Final StringBuffer b=new StringBuffer ("not immutable");
a=b;//Compile-time error
Final StringBuffer a=new StringBuffer ("immutable");
Final StringBuffer b=new StringBuffer ("not immutable");
a=b;//Compile-time error
The object that the reference points to is the same:
Final StringBuffer a=new StringBuffer ("immutable");
A.append ("broken!"); Compiled by
Final StringBuffer a=new StringBuffer ("immutable");
A.append ("broken!"); Compiled by
As you can see, final is valid only for the referenced "value" (the memory address of the object it points to), forcing the reference to point only to the object that was initially pointed at, and changing its point to cause a compile-time error. Final is not responsible for the change in the object it points to. This is similar to the = = Operator: the = = operator is only responsible for the reference "value" equality, as to whether the address points to the object content is equal, the = = operator is no matter. In an example:
public class Name {
Private String FirstName;
Private String LastName;
Public String Getfirstname () {
return FirstName;
}
public void Setfirstname (String firstname) {
This.firstname = FirstName;
}
Public String Getlastname () {
return lastname;
}
public void Setlastname (String lastname) {
This.lastname = LastName;
}
}
public class Name {
Private String FirstName;
Private String LastName;
Public String Getfirstname () {
return FirstName;
}
public void Setfirstname (String firstname) {
This.firstname = FirstName;
}
Public String Getlastname () {
return lastname;
}
public void Setlastname (String lastname) {
This.lastname = LastName;
}
}
编写测试方法:
public static void Main (string[] args) {
Final name name = new name ();
Name.setfirstname ("JIM");
Name.setlastname ("Green");
System.out.println (Name.getfirstname () + "" +name.getlastname ());
}
public static void Main (string[] args) {
Final name name = new name ();
Name.setfirstname ("JIM");
Name.setlastname ("Green");
System.out.println (Name.getfirstname () + "" +name.getlastname ());
}
理解final问题有很重要的含义。许多程序漏洞都基于此----final只能保证引用永远指向固定对象,不能保证那个对象的状态不变。在多线程的操作中,一个对象会被多个线程共享或修改,一个线程对对象无意识的修改可能会导致另一个使用此对象的线程崩溃。一个错误的解决方法就是在此对象新建的时候把它声明为final,意图使得它"永远不变"。其实那是徒劳的。 Final还有一个值得注意的地方: 先看以下示例程序:
Class Something {
final int i;
public void dosomething () {
System.out.println ("i =" + i);
}
}
Class Something {
final int i;
public void dosomething () {
System.out.println ("i =" + i);
}
}
For class variables, the Java virtual opportunity is automatically initialized. If the initial value is given, it is initialized to that initial value. If not given, it is initialized to the default initial value of the type variable. But for a class variable that is final decorated, the virtual machine does not give it an initial value, and must be given a definite constructor before the end of the constructor. Can be modified to "final int i = 0;".
- How to write a program more robust:
1. Release the reference of the useless object as soon as possible. A good idea is to use a temporary variable when the reference variable is automatically set to null after exiting the active domain, implying that the garbage collector collects the object to prevent a memory leak. For instances where pointers are still pointing, the JVM does not reclaim the resource because garbage collection will use null-valued objects as garbage, increasing the efficiency of the GC recovery mechanism;
2, the definition string should try to use string str= "Hello"; form, avoid using string str = new string ("Hello"); The form. Because you want to use the same content string, you don't have to new a string every time. For example, we want to initialize a string reference variable named S in the constructor, set it to the initial value, and should do this:
public class Demo {
Private String S;
Public Demo () {
s = "Initial Value";
}
}
Public class Demo {
Private String s;
...
Public Demo {
s = "Initial Value";
}
...
}
Rather than
S = new String ("Initial Value");
S = new String ("Initial Value"); The
latter invokes the constructor every time, generating new objects, performance and memory overhead, and meaningless, because the string object is immutable, so for a string of the same content, as long as a string object is represented. It also says that multiple calls to the above constructor create several objects whose string type property s all point to the same object.
3, our program is inevitably a lot of string processing, avoid using string, should use a lot of stringbuffer, because string is designed to be immutable (immutable) class, so all its objects are immutable objects, see the following code;
String s = "Hello";
s = s + "world!";
String s = "Hello";
s = s + "world!";
In this code, s originally pointed to a string object, the content is "Hello", and then we have a + operation on S, then the object pointed to by S has changed it? The answer is no. At this point, S does not point to the original object, and point to another string object, the content is "Hello world!", the original object is still in memory, but s this reference variable no longer points to it. With the instructions above, it is easy to derive another conclusion that if you frequently make a variety of changes to the string, or if the changes are unpredictable, then using string to represent the strings can cause significant memory overhead. Because a string object cannot be changed after it is established, a string object is required for each different string. At this point, you should consider using the StringBuffer class, which allows you to modify instead of creating a new object for each different string. Also, the conversion of these two kinds of objects is very easy.
4, minimize the use of static variables, because the static variables are global, the GC will not be recycled;
5, try to avoid in the constructor of the class to create, initialize a large number of objects, to prevent the invocation of its own class of the constructor to cause unnecessary waste of memory resources, especially large objects, the JVM will suddenly require a large amount of memory, it will inevitably trigger the GC optimization system memory environment; The following are the time consuming to initialize different types of objects:
Arithmetic operations
Example
Standardized time
Locally assigned value
i = n
1.0
Instance Assignment value
THIS.I = n
1.2
Method invocation
Funct ()
5.9
New Object
New Object ()
980
New array
New INT[10]
3100
As you can see from table 1, creating a new object takes 980 units of time, is 980 times times the local assignment time, is 166 times times the method invocation time, and it takes more time to create a new array.
6, as far as possible in the appropriate scenario to use the object pool technology to improve system performance, reduce the cost, but pay attention to the size of the object pool should not be too large, timely elimination of invalid objects to free memory resources, comprehensive consideration of the application running environment memory resource limitations, to avoid overestimation of the running environment to provide the amount of memory resources.
7, large collection objects have large data volume of business objects, you can consider chunking to deal with, and then solve a piece of the strategy to release a piece.
8. Do not create objects in frequently invoked methods, especially when creating objects in loops. You can use Hashtable,vector to create a set of object containers and then fetch those objects from the container without having to discard them each time you new.
9, generally occurs in the opening of large files or with the database once took too much data, resulting in the state of the memory Error, it is likely to calculate the maximum amount of data, and set the required minimum and maximum memory space value.
10, minimize the use of the Finalize function, because finalize () will increase the workload of GC, and GC equivalent to the cost of the system's computing power.
11, do not use the hash table, a certain development experience of developers often use hash tables (hash table in the JDK is an implementation is HashMap) to cache some data, thereby increasing the speed of the system. For example, the use of HashMap cache some material information, personnel information and other basic information, which improves the system speed, but also increased the system's memory, especially when the cache of more data. In fact, we can use the concept of caching in the operating system to solve this problem, that is, to allocate a cache of a certain size cache container, according to a certain algorithm to eliminate the need to continue to cache the object, on the one hand, because of the object cache and improve the system's operational efficiency, It also reduces the memory footprint of the system because the cache container is not infinitely expanded. Now there are many open source cache implementation projects, such as Ehcache, Oscache, etc., these projects have implemented the FIFO, MRU and other common cache algorithm
Java Memory Management mechanism