java 之 内存结构与垃圾回收机制算法分析

jvm运行时内存划分
1.方法区:类的信息,常量,静态 (1.8前叫永久区)
2.堆内存:new 出来的对象,数组,
3.java栈 :基本数据类型,局部变量(每个线程独立栈)
4.本地方法栈:java调用外部语言(c语言),方法使用native(CAS),安卓开发,应用层 java api 底层 C 语言 JNI
5.程序计数器 :是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器。
java 之 内存结构与垃圾回收机制算法分析_第1张图片
下面来说一下堆内存的划分

堆内存划分为:新生代老年代 默认大小为1:2
新生代又划分为:eden区from区to区 默认大小为2:1:1
如下图所示:
如下图片

新生代 :刚出生不久的对象 或者 不经常使用的对象
老年代 :存放比较活跃的对象 经常被引用(使用)的对象

什么是垃圾回收机制?
就是不定时去堆内存中清理不可达对象(没有存活的对象)。不可达的对象并不会马上就会直接回收, 垃圾收集器在一个Java程序中的执行是自动的

如何判断对象是否存活?
引用计数法
引用计数法就是如果一个对象没有被任何引用指向,则可视之为垃圾。这种方法的缺点就是不能检测到环的存在。
首先需要声明,至少主流的Java虚拟机里面都没有选用引用计数算法来管理内存。
什么是引用计数算法:给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值加1;当引用失效时,计数器值减1.任何时刻计数器值为0的对象就是不可能再被使用的。
那为什么主流的Java虚拟机里面都没有选用这种算法呢?
其中最主要的原因是它很难解决对象之间相互循环引用的问题。

根搜索算法
根搜索算法的基本思路就是通过一系列名为”GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。
那么问题又来了,如何选取GCRoots对象呢?
在Java语言中,可以作为GCRoots的对象包括下面几种:
(1). 虚拟机栈(栈帧中的局部变量区,也叫做局部变量表)中引用的对象。
(2). 方法区中的类静态属性引用的对象。
(3). 方法区中常量引用的对象。
(4). 本地方法栈中JNI(Native方法)引用的对象。
如下图所示
java 之 内存结构与垃圾回收机制算法分析_第2张图片
由上图可以看出 obj8,obj9,obj10 是不可用对象,因为没有任何一个GC Roots与之相连,便是GC Roots不可达的对象,也就是GC需要回收的垃圾对象。

垃圾回收机制策略

标记清除算法
该算法有两个阶段。

  1. 标记阶段:找到所有可访问的对象,做个标记
  2. 清除阶段:遍历堆,把未被标记的对象回收

复制算法
如果jvm使用了copy算法,一开始就会将可用内存分为两块,from域和to域, 每次只是使用from域,to域则空闲着。当from域内存不够了,开始执行GC操作,这个时候,会把from域存活的对象拷贝到to域,然后直接把from域进行内存清理,如此交换15次(由JVM参数MaxTenuringThreshold决定,这个参数默认是15),最终如果还是存活,就存入到老年代

标记压缩算法
标记清除算法和标记压缩算法非常相同,但是标记压缩算法在标记清除算法之上解决内存碎片化
,因为他会将所有的不可达对象排序到一块,所有不会造成内存碎片化。
如下图所示
java 之 内存结构与垃圾回收机制算法分析_第3张图片
压缩算法介绍
任意顺序 : 即不考虑原先对象的排列顺序,也不考虑对象之间的引用关系,随意移动对象;
线性顺序 : 考虑对象的引用关系,例如a对象引用了b对象,则尽可能将a和b移动到一块;
滑动顺序 : 按照对象原来在堆中的顺序滑动到堆的一端。

你可能感兴趣的:(jvm,jvm)