不得不看的JVM内存管理

作为一个任何完整的机器都会有内存管理这块组成结构。作为jvm也有自己的内存管理。

 

 

1.那么在java中哪些组件需要使用内存。

a)        Java堆

b)       线程:线程是在jvm运行实际程序的实体

c)        类和类加载器:jvm只会加载一个类到内存一次

d)       NIO

e)        JNI:java本地接口

 

2那么JVM内存结构是什么?

其实jvm的内存结构是按照运行时数据的存储结构来划分内存结构的。

而在JVMjava运行时数据分为6种:

a)        pc寄存器:是一种数据结构,用来保存当前正常执行的程序内存地址。

b)       java栈:当线程创建就会建立对应的栈。但是这个数据线程是不共享的,所以无同步锁。

c)        堆:java存储数据的地方。

d)       方法区:是一种特殊的堆,是堆的永久区

e)        本地方法区:

f)        运行常量池

 

 

上面说的六种其实主要永久就是堆和栈

 

3.那么我说说堆和栈的区别

栈和线程密切相关。所以一个线程的创建对建立对应的栈,栈这种数据结构存储数据快,而且只要数据存放在栈中,在编译的时候就给分配内存空间的。既然在编译的时候分配了内存空间,这不就说明了一个问题,栈的大小和生命周期是确定的。想想这些确定的数据所以存储的数据就是一些基本的数据类型和句柄对象(引用)。比如说一说int这些基本类型我们就知道我们会给他分配一个四个字节的大小。所以这些在编译的时候都能完成。而且要知道栈中的数据是共享的。

堆是一种运行时数据,在运行时候给他分配大小。所以他的优势就是特别灵活。而且我们所说的GC就是针对堆说的。堆我们都知道存放的是对象。所以一般new,newarray,等指令建立都会存放在堆中。

 

所以总结堆和栈的区别:在栈中数据大小确定,生命周期确定,运行速度快,仅次与寄存器,数据共享,一般存放基本数据结构和引用类型。但是缺少灵活行。堆用来存放对象,在运行时创建对象,数据灵活,对象的回收通过gc机制。由于动态存储所以速度就慢。

                                                                                     

前面说了堆的一点小知识,也说了gc。

4.那么gc的原理是什么?

Gc就是垃圾回收器。垃圾回收器必须能完成两件事情:一个能够正确检测垃圾对象,一个能释放对象占内存的空间。

所以看到上面话的定义相信很清楚,gc是针对对象的。对象存放在堆中,所以上面我说的不虚。

Gc的原理就是首先我们将所有的对象描绘成一棵树形结构,然后通过遍历算法搜索这棵树,从根一直遍历。如果能遍历得到对象我们称这是活动对象,如果不能遍历到就说这个对象是非活动的对象。对于非活动对象就是相对与内存的垃圾,只占内存空间资源,但是我们却调用不到。对于这样的对象我们就将其销毁。

 

 

 

 

为了提高垃圾回收的效率,人们发明一个分代算法。分代顾名思义就是将对象按照年龄划分。分年轻代和年老代。对于新建的对象对象被划分在年轻代,如果对象经过回收仍然存活就把他调到年老代。那么我们每次扫描就频繁扫描年轻代,年老调用的较少就次数扫描的少。这样做的好处就是可以减少扫描的次数。从而提高gc效率.

 

 

5还有关于内存溢出。首先明白一点,内存溢出的原因是什么?

 

内存溢出就是所有占用内存的组件(我最开始说的那几种)在内存中一直占用资源,且不断增加,而内存大小固定。那么这种情况资源迟早会用完就会出现内存溢出。

所以你应该明白一点。内存溢出不仅仅是堆数据溢出(对象溢出)。这只是一个方面。当然了。只要有东西占用内存这个东西就用可能造成数据溢出。

在显示生活中堆和栈的溢出是很常见的。

比如说一个对象创建了,但是呢对象用完了其实就没有意义了。应该及时释放。可是没有释放。这样的垃圾对象一多就容易内存溢出。这是关于堆溢出的

还有比如说一个循for int i=0;i<10000;i++){}这里的i就是在这里用那么一下,所以他的生命周期在这里用完就行了。可是有人却非要把这个生命周期延长。把int i定义在外面。

这样一循环完了但是int i会一直存在,这样他就一直在栈中占据内存。这就是一种短周期的东西非要用长生命周期使用。这种东西一多就造成内存的浪费,就是一种栈溢出。

 

 

 

原文地址:https://www.cnblogs.com/keanuyaoo/p/3343438.html