JVM内存管理和垃圾回收
无论对于Java程序员还是大数据研发人员,JVM是必须掌握的技能之一。既是面试中经常问的问题,也是在实际业务中对程序进行调优、排查类似于内存溢出、栈溢出、内存泄漏等问题的关键。笔者将按下图分多篇文章详细阐述JVM:
本篇文章主要叙述JVM内存管理、直接内存、垃圾回收和常见的垃圾回收算法:
运行时数据区域
JVM在执行一些基于JVM运行的程序,典型的如Java程序、Scala程序时,会把它所管理的内存划分为多个不同的数据区域。这些区域有各个的作用、创建和销毁时间,有的区域生命周期依赖于用户线程的启动和结束,有些区域则随着虚拟机的启动而存在,下图展示了JVM在运行时的数据区域划分:
1. 方法区
方法区是各个线程共享的内存区域,主要用于存放一些"自始至终都不会变化"的东西,比如final定义的常量、类的信息(class实例)、静态变量等、方法信息。因为这些东西一旦被加载,是几乎不会被GC的,所以方法区又被称为永久代(注意一点,二者本质并不等价)。
方法区有一部分叫常量池,用于存储编译期生成的一些字面变量、符号引用以及一些运行时产生的常量(如String常量池)。方法区中的静态区用于存放类变量、静态块等。
方法区又称非堆,是有大小限制的,如果方法区使用内存超过了分配的大小,就会报类似OutOfMemory: PermGen Space的错误。
2. Java虚拟机栈
Java 虚拟机栈是线程私有的,它的生命周期与线程相同,为虚拟机执行Java方法即字节码服务,是描述Java方法执行时的内存模型。
每个方法执行时都会创建一个栈帧用于存储局部变量表(比如编译期可知的基本数据类型、对象引用等)、操作栈、动态链接、方法出口等信息。每一个方法被调用至执行完成的过程,对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
如果线程请求的栈深度大于虚拟机所允许的深度,将会报StackOverFlowError;如果虚拟机栈无法申请到足够的内存时会报OutOfMemoryError。
调整虚拟机栈大小的方式:-Xss。
3. 本地方法栈
本地方法栈为使用的到Native方法服务,本地方法接口都会使用某种本地方法栈。
当线程调用Java方法时,虚拟机会创建一个新的栈帧并压入Java栈。然而,当它调用的是本地方法时,虚拟机会保持Java栈不变,不会在线程的Java栈中压入新的栈帧,而是动态连接并直接调用指定的本地方法。
4. 堆
堆是JVM管理内存中最大的一块区域,由Java线程共享,主要用来存储new出来的对象和数组,并且这块区域随着虚拟机的启动而创建。堆可以处于逻辑上连续但物理上不连续的内存空间中。
堆是垃圾回收器管理的主要区域,可以细分为新生代和老年代,新生代又划分为eden区,from survivor区、to survivor区。
对象在被创建时,首先在新生代进行分配,eden区存放新生成的对象,两个survivor区用来存放新生代中每次垃圾回收后依然存活下来的对象。但是当创建新创建的对象非常大,该对象会直接进入老年代。
5. 程序计数器
程序计数器是线程私有的即每个线程都会有自己的程序计数器,用来记录线程执行的字节码位置,是一个没有OOM的区域。
直接内存
直接内存(direct memory)不属于JVM运行时数据区的一部分,属于堆外内存,会被频繁使用,因此在设置各个内存范围时要留出一部分物理内存,否则也容易抛出OutOfMemoryError。
垃圾收集
垃圾收集即GC,是JVM进行内存回收的处理过程。
开发人员更多的是关注业务需求的实现,而内存管理是交由JVM完成的,如果不进行或者错误的进行垃圾回收会导致程序不稳定甚至崩溃。Java提供的GC功能可以自动监测对象是否超过作用域等从而达到自动回收内存的目的,可以有效防止内存泄露,有效的使用可用内存。
GC主要分为3种:minor GC、major GC和full GC。
minor GC是发生在新生代的,minor GC是发生在老年代的。对于full GC出发的原因则比较多,比如老年代空间不足,它会出发stop world,处理不好往往会影响整个程序的稳定性严重会导致系统不可用,需要特别注意。
常见的垃圾回收算法
1. 标记清除算法
首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。存在如下两个缺点:1.效率低需要先对要回收的对象进行标记,然后再统一清除,然而标记和清除两个过程效率都很低下。2.内存碎片问题标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作,影响性能。
2. 复制算法
先将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当使用的这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。
优点:这样使得每次都是对整个半区进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可,实现简单,运行高效。
缺点:不适合对象存活率较高的场景,因为这种场景要进行较多的复制操作影响效率;实际可用内存变为分配内存的一半,因为每次只使用其中的一半内存。
3. 标记整理算法
先标记(标记过程与标记清除算法一样),让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。这样可以解决内存碎片问题。
4. 分代收集算法
就是针对Java堆内存中新生代、老年代等采用不同的垃圾回收算法。如在新生代中,往往只有少量对象存活(最后会进入老年代),则适合用复制算法。而老年代中对象存活率较高,没有额外的空间对它进行分配担保,就使用标记清除算法。
当然实际应用中,使用什么算法,要看使用的垃圾回收器。
关注微信公众号:大数据学习与分享,获取更对技术干货
JVM内存管理和垃圾回收的更多相关文章
- Java之美[从菜鸟到高手演变]之JVM内存管理及垃圾回收
很多Java面试的时候,都会问到有关Java垃圾回收的问题,提到垃圾回收肯定要涉及到JVM内存管理机制,Java语言的执行效率一直被C.C++程序员所嘲笑,其实,事实就是这样,Java在执行效率方面确 ...
- JVM内存管理及垃圾回收【转】
很多Java面试的时候,都会问到有关Java垃圾回收的问题,提到垃圾回收肯定要涉及到JVM内存管理机制,Java语言的执行效率一直被C.C++程序员所嘲笑,其实,事实就是这样,Java在执行效率方面确 ...
- JVM原理(Java代码编译和执行的整个过程+JVM内存管理及垃圾回收机制)
转载注明出处: http://blog.csdn.net/cutesource/article/details/5904501 JVM工作原理和特点主要是指操作系统装入JVM是通过jdk中Java.e ...
- JVM内存管理和垃圾回收机制介绍
http://backend.blog.163.com/blog/static/20229412620128233285220/ 内存管理和垃圾回收机制是JVM最核心的两个组成部分,对其内部实 ...
- JVM内存管理及垃圾回收
一.JVM内存的构 Java虚拟机会将内存分为几个不同的管理区,这些区域各自有各自的用途,根据不同的特点,承担不同的任务以及在垃圾回收时运用不同的算法.总体分为下面几个部分: 程序计数器(Progra ...
- JVM内存管理及垃圾回收机制
一.JVM内存组成结构 JVM栈由堆.栈.本地方法栈.方法区等部分组成,结构图如下所示: 二.JVM内存回收 Sun的JVMGenerationalCollecting(垃圾回收)原理是这样的:把对 ...
- (转)JVM——内存管理和垃圾回收
背景:对JVM的垃圾回收算法进行系统的总结. 转载:http://blog.csdn.net/SEU_Calvin/article/details/51892567 1. 何为GC Java与C语言 ...
- JVM——内存管理和垃圾回收
1. 何为GC 转载请注明出处:http://blog.csdn.net/seu_calvin/article/details/51892567 Java与C语言相比的一个优势是,可以通过自己的JV ...
- JVM内存管理 + GC垃圾回收机制
2.JVM内存管理 JVM将内存划分为6个部分:PC寄存器(也叫程序计数器).虚拟机栈.堆.方法区.运行时常量池.本地方法栈 PC寄存器(程序计数器):用于记录当前线程运行时的位置,每一个线程都有一个 ...
随机推荐
- day54:django:锁和事务&Ajax&中间件Middleware
目录 1.ORM中的锁和事务 2.Ajax 3.中间件:Middleware 3.1 什么是中间件? 3.2 django请求的生命周期 3.3 中间件可以定义的5个方法 3.4 自定义中间件的流程 ...
- 海量数据处理之布隆过滤器BloomFilter算法
Bloom Filter是由Bloom在1970年提出的一种多哈希函数映射的快速查找算法.通常应用在一些需要快速判断某个元素是否属于集合,但是并不严格要求100%正确的场合.使用场景:数据量为100亿 ...
- Nodejs-原型链污染
原型链污染 javascript 原型链 在javascript中,继承的整个过程就称为该类的原型链. 每个对象的都有一个指向他的原型(prototype)的内部链接,这个原型对象又有它自己的原型,一 ...
- Java环境变量配置 新手必备
第一步:安装JDK,无脑下一步 建议修改安装路径 这里以jdk1.7为例子(之前帮机房安装软件,五六十台电脑都要用1.7); 2.安装完了之后右击此电脑,打开属性 打开系统高级设置 打开环境变量 这里 ...
- Alink漫谈(二十二) :源码分析之聚类评估
Alink漫谈(二十二) :源码分析之聚类评估 目录 Alink漫谈(二十二) :源码分析之聚类评估 0x00 摘要 0x01 背景概念 1.1 什么是聚类 1.2 聚类分析的方法 1.3 聚类评估 ...
- 普转提Day2
T1 给定一个区间,求这个区间中只有一个数字与其他数组不相同的数的个数. 给出的区间范围较大,但是要求的数比较少.所以我的想法是这样的:因为这些数只有一个数字和每个数字都相同的数不同,所以考虑将所有数 ...
- Python-类属性查询协议-__getattr__ __getattribute__
__getattr__ 查找不到类属性的时候调用 class BeiMenChuiXue: def __init__(self, name): self.name = name def __getat ...
- Centos-显示或修改系统时间与日期-date
date 显示或者修改系统时间与日期,只有超级用户才能用date命令设置和修改时间,普通用户只能显示时间 相关参数 -s 设置设置时间,格式为 Y-m-d H:M:S -d 对日期进行运算, + ...
- # mac使用homebrew安装jdk和tomcat
homebrew安装jdk 前提是已经安装homebrew //直接命令行安装 brew cask install homebrew/cask-versions/adoptopenjdk8 homeb ...
- 借助C++探究素数的分布
这里使用的区间是36,144,576,2304,9216,36864,147456,589824,2359296,9437184.至于这个区间是怎么得到的,感兴趣的同鞋可前往(https://www. ...