Java内存管理及GC算法

概述

内存划分

虚拟机规范中将内存分为六大部分,分别为PC寄存器、JAVA虚拟机栈、JAVA堆、方法区、运行时常量及本地方法栈。

1.PC寄存器:线程独占
2.JAVA虚拟机栈:线程独有;JAVA虚拟机栈是在创建线程的同时创建的,用于存储栈帧,JAVA虚拟机栈也是线程独有的。
3.JAVA堆:全局共享
4.方法区:全局共享;它主要存储的是

  • 运行时常量池
  • 字段信息
  • 方法信息
  • 构造方法
  • 普通函数的字节码内容以及一些特殊方法。
    5.本地方法栈:线程独有,本地方法栈是一个传统的栈,它用来支持native方法的执行。如果JAVA虚拟机是使用的其它语言实现指令集解释器的时候,也会用到本地方法栈。

内存管理

1.一部分是全局共享:

  • JAVA堆
  • 方法区
    2.一部分是线程独有
  • PC寄存器
  • JAVA虚拟机栈
  • 本地方法栈

GC简介及算法

GC策略解决了哪些问题?

内存作为一种有限的资源,然而随着时间的推移内存的垃圾会越来越多。但java并没有提供类似于C/C++这一类内存释放和管理的机制,而是通过内置的GC进行内存的管理。GC的主要工作是:

1.哪些对象可以被回收?
2.何时回收?
3.采用什么样的方式回收?

GC策略采用的何种算法

有一种比较简单直观的办法,它的效率较高,被称作引用计数算法。但是这个算法有一个致命的缺陷,那就是对于循环引用的对象无法进行回收。

根搜索算法(解决哪些对象可以被回收的问题)

由于引用计数算法的缺陷,所以JVM一般会采用一种新的算法,叫做根搜索算法。它的处理方式就是,设立若干种根对象,当任何一个根对象到某一个对象均不可达时,则认为这个对象是可以被回收的。

GC roots(GC根),在JAVA语言中,可以当做GC roots的对象有以下几种:

  • 虚拟机栈中的引用的对象。
  • 方法区中的类静态属性引用的对象。
  • 方法区中的常量引用的对象。(final)
  • 本地方法栈中JNI的引用的对象。
    第一和第四种都是指的方法的本地变量表,第二种表达的意思比较清晰,第三种主要指的是声明为final的常量值。

垃圾收集算法

垃圾搜集的算法主要有三种,分别是标记-清除算法复制算法标记-整理算法。这三种算法都扩充了根搜索算法。

标记-清除算法

当堆中的有效内存空间(available memory)被耗尽的时候,就会停止整个程序(也被成为stop the world),然后进行两项工作,第一项则是标记第二项则是清除

  • 标记:标记的过程其实就是,遍历所有的GC Roots,然后将所有GC Roots可达的对象标记为存活的对象。
  • 清除:清除的过程将遍历堆中所有的对象,将没有标记的对象全部清除掉。

通俗地说也就是当可用内存即将耗尽时,逐步完成以下工作:

  • 1.GC线程就会被触发并将程序暂停;
  • 2.将依旧存活的对象标记起来;
  • 3.将堆中未标记的对象全部清除;
  • 4.程序恢复运行。

缺陷:

  • 1、首先,它的缺点就是效率比较低(递归与全堆对象遍历),而且在进行GC的时候,需要停止应用程序,这会导致用户体验非常差劲
  • 2、第二点主要的缺点,则是这种方式清理出来的空闲内存是不连续的

复制算法

复制算法由“标记-清除算法”基础上演化而来。

复制算法将内存划分为两个区间,在任意一个时间点,所有动态分配的对象只能分配在其中一个区间(活动区间),而另一个区间(空闲区间)则是空闲的。

当可用内存即将耗尽时,会逐步完成以下工作:

  • 1.GC线程就会被触发并将程序暂停;
  • 2.将依旧存活的对象标记起来;
  • 3.将存活对象全部复制到空闲区间,且严格按照内存地址依次排序;
  • 4.将存活对象引用指向新地址;
  • 5.将活动区间转换成空闲区间,并一次性全部回收所有垃圾对象;
  • 6.程序恢复运行。

复制算法弥补了标记-清除算法中内存布局混乱的缺点,但其缺点也很明显:

  • 浪费了一半的内存,也就是说有一半的内存空间是闲置的;
  • 如果对象的存活率很高,我们可以极端一点,假设是100%存活,那么我们需要将所有对象都复制一遍,并将所有引用地址重置一遍。复制这一工作所花费的时间,在对象存活率达到一定程度时,将会变的不可忽视。

复制算法要想使用,最起码对象的存活率要非常低才行,而且最重要的是,我们必须要克服50%内存的浪费。

标记-整理算法

标记-整理算法标记-清除算法类似,可以分成两个阶段:标记和整理

  • 1.标记:它的第一个阶段与标记/清除算法是一模一样的,均是遍历GC Roots,然后将存活的对象标记。
  • 2.整理:移动所有存活的对象,且按照内存地址次序依次排列,然后将末端内存地址以后的内存全部回收。因此,第二阶段才称为整理阶段。

优点:标记/整理算法不仅可以弥补标记/清除算法当中,内存区域分散的缺点,也消除了复制算法当中,内存减半的高额代价
缺点:标记/整理算法唯一的缺点就是效率也不高

复制算法、标记/整理算法、标记/清除算法共同点:

  • 1、三个算法都基于根搜索算法去判断一个对象是否应该被回收,而支撑根搜索算法可以正常工作的理论依据,就是语法中变量作用域的相关内容。因此,要想防止内存泄露,最根本的办法就是掌握好变量作用域,而不应该使用前面内存管理杂谈一章中所提到的C/C++式内存管理方式。
  • 2、在GC线程开启时,或者说GC过程开始时,它们都要暂停应用程序(stop the world)。

区别:

  • 效率:复制算法>标记/整理算法>标记/清除算法(此处的效率只是简单的对比时间复杂度,实际情况不一定如此)。
  • 内存整齐度:复制算法=标记/整理算法>标记/清除算法。
  • 内存利用率:标记/整理算法=标记/清除算法>复制算法。

分代搜集算法

没有最好的算法,只有最合适的算法,不同算法适合不同的场景。

  • 新生代或者年轻代【普通GC(minor GC)】:适合使用复制算法
  • 年老代【全局GC(major GC or Full GC)】:采用标记/整理或者标记/清除算法
时间: 2024-11-08 18:50:27

Java内存管理及GC算法的相关文章

JVM内存管理:GC算法精解---分代搜集算法

引言 何为终极算法? 其实就是现在的JVM采用的算法,并非真正的终极.说不定若干年以后,还会有新的终极算法,而且几乎是一定会有,因为LZ相信高人们的能力. 那么分代搜集算法是怎么处理GC的呢? 对象分类 上一章已经说过,分代搜集算法是针对对象的不同特性,而使用适合的算法,这里面并没有实际上的新算法产生.与其说分代搜集算法是第四个算法,不如说它是对前三个算法的实际应用. 首先我们来探讨一下对象的不同特性,接下来LZ和各位来一起给这些对象选择GC算法. 内存中的对象按照生命周期的长短大致可以分为三种

JVM内存管理:GC算法精解(五分钟让你彻底明白标记/清除算法)

首先,我们回想一下上一章提到的根搜索算法,它可以解决我们应该回收哪些对象的问题,但是它显然还不能承担垃圾搜集的重任,因为我们在程序(程序也就是指我们运行在JVM上的JAVA程序)运行期间如果想进行垃圾回收,就必须让GC线程与程序当中的线程互相配合,才能在不影响程序运行的前提下,顺利的将垃圾进行回收. 为了达到这个目的,标记/清除算法就应运而生了.它的做法是当堆中的有效内存空间(available memory)被耗尽的时候,就会停止整个程序(也被成为stop the world),然后进行两项工

JVM内存管理:GC算法精解(复制算法与标记/整理算法)

本次LZ和各位分享GC最后两种算法,复制算法以及标记/整理算法.上一章在讲解标记/清除算法时已经提到过,这两种算法都是在此基础上演化而来的,究竟这两种算法优化了之前标记/清除算法的哪些问题呢? 复制算法 我们首先一起来看一下复制算法的做法,复制算法将内存划分为两个区间,在任意时间点,所有动态分配的对象都只能分配在其中一个区间(称为活动区间),而另外一个区间(称为空闲区间)则是空闲的. 当有效内存空间耗尽时,JVM将暂停程序运行,开启复制算法GC线程.接下来GC线程会将活动区间内的存活对象,全部复

java内存管理(堆、栈、方法区)

java内存管理 简介 首先我们要了解我们为什么要学习java虚拟机的内存管理,不是java的gc垃圾回收机制都帮我们释放了内存了吗?但是在写程序的过程中却也往往因为不懂内存管理而造成了一些不容易察觉到的内存问题,并且在内存问题出现的时候,也不能很快的定位并解决.因此,了解并掌握Java的内存管理是我们必须要做的是事,也只有这样才能写出更好的程序,更好地优化程序的性能. 概述 Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干不同的数据区域,这些区域都有各自的用途以及创建和销毁

Java内存管理

版权声明:本文为博主原创文章,转载注明出处http://blog.csdn.net/u013142781 前一段时间粗略看了一下<深入Java虚拟机 第二版>,可能是因为工作才一年的原因吧,看着十分的吃力.毕竟如果具体到细节的话,Java虚拟机涉及的内容太多了.可能再过一两年去看会合适一些吧. 不过看了一遍<深入Java虚拟机>再来理解Java内存管理会好很多.接下来一起学习下Java内存管理吧. 请注意上图的这个: 我们再来复习下进程与线程吧: 进程是具有一定独立功能的程序关于某

java内存管理和回收机制

java类文件是以 .java为后缀的文件,经过javac命令编译后,编译成class文件,class文件中都是二进制格式的数据,所以想要看编译后的内容是什么,可以采用jdk自带的javap命令查看. JVM中有个组成部分为类加载器(ClassLoader),负责java文件编译后class文件的加载,加载到哪呢,加载到内存.那下面来说一下JVM的内存管理. java通过类加载器来加载class文件,加载到内存后,会把类.方法.常变量放到堆内存中.因为java是自动进行垃圾回收的,所以放入堆内存

JVM内存管理及GC机制

一.概述 Java GC(Garbage Collection,垃圾收集,垃圾回收)机制,是Java与C++/C的主要区别之一,作为Java开发者,一般不需要专门编写内存回收和垃圾清理代码,对内存泄露和溢出的问题,也不需要像C程序员那样战战兢兢.经过这么长时间的发展,Java GC机制已经日臻完善,几乎可以自动的为我们做绝大多数的事情. 虽然java不需要开发人员显示的分配和回收内存,这对开发人员确实降低了不少编程难度,但也可能带来一些副作用: 1. 有可能不知不觉浪费了很多内存 2. JVM花

JAVA 内存管理总结

1. java是如何管理内存的 Java的内存管理就是对象的分配和释放问题.(两部分) 分配 :内存的分配是由程序完成的,程序员需要通过关键字new 为每个对象申请内存空间 (基本类型除外),所有的对象都在堆 (Heap)中分配空间. 释放 :对象的释放是由垃圾回收机制决定和执行的,这样做确实简化了程序员的工作.但同时,它也加重了JVM的工作.因为,GC为了能够正确释放对象,GC必须监控每一个对象的运行状态,包括对象的申请.引用.被引用.赋值等,GC都需要进行监控. 2. 什么叫java的内存泄

Java内存管理和垃圾回收

笔记,深入理解java虚拟机   Java运行时内存区域 程序计数器,线程独占,当前线程所执行的字节码的行号指示器,每个线程需要记录下执行到哪儿了,下次调度的时候可以继续执行,这个区是唯一不会发生oom的 栈,线程独占,包含虚拟机栈或native method stack,用于存放局部变量的 堆,线程共享,用于分布对象实例的,后面说的内存管理和垃圾回收基本都是针对堆的 方法区,线程共享,用于存放被虚拟机加载的类,常量,静态变量; Java虚拟机规范,把方法区描述为堆的逻辑部分,所以也被称为"永久