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寄存器(程序计数器):用于记录当前线程运行时的位置,每一个线程都有一个 ...
随机推荐
- CentOS7使用yum时File contains no section headers.解决办法
本文转载于 https://blog.csdn.net/trokey/article/details/84908838 安装好CenOS7后,自带的yum不能直接使用,使用会出现如下问题: 原因是没 ...
- JELLY技术周刊 Vol.23: Vue3 是伟大航路上的 One Piece 么?
蒲公英 · JELLY技术周刊 Vol.23 这两天大家应该都被 Vue 发布 3.0 版本的信息刷屏了,背负着很多人的期待, Vue 终于将这个船新版本推到台前,接受大众的检验,那么这个代号为 On ...
- jpeg编解码概述
本博文为概览性介绍.后面有空了再分几篇博文分别介绍所用到的技术细节. 1.编解码目标 编码和解码是个逆过程.jpeg编码的目的在于图形去冗余,进行数据压缩,解码的目的在于还原图像,使能够进行预览. 2 ...
- Spring 的依赖注入应用代替工厂模式
接口 package FactoryExample; public interface Human { void eat(); void walk(); void show(); } 实现 实现一 p ...
- 【译】使用 WebView2 将最好的 Web 带到 .NET 桌面应用程序中
在去年的 Build 大会上,我们引入了 WebView2,这是一个浏览器控件,可以用新的基于 Chrome 的 Microsoft Edge 来呈现 Web 内容(HTML / CSS / Java ...
- 078 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 01 初识面向对象 03 创建类
078 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 01 初识面向对象 03 创建类 本文知识点:创建类 说明:因为时间紧张,本人写博客过程中只是对知识点的关 ...
- Eclipse 重命名工程、包、类
Eclipse版本 重命名工程,使用鼠标右键点击工程,选Refactor > Rename...(快捷键:Alt + Shift + R) 重命名包.类的操作与重命名工程一样. 其实,最简单的操 ...
- P 3396 哈希冲突 根号分治
Link 据说这是一道论文题????.具体论文好像是 集训队论文<根号算法--不只是分块> 根号分治的裸题. 首先我们考虑暴力怎么打. 先预处理出每个模数的答案,之后再 O(1) 的回答, ...
- 优质分享 | Spring Boot 入门到放弃!!!
持续原创输出,点击上方蓝字关注我 目录 前言 视频目录 如何获取? 总结 前言 最近不知不觉写Spring Boot专栏已经写了九篇文章了,从最底层的项目搭建到源码解析以及高级整合的部分,作者一直在精 ...
- PJzhang:鸟哥的linux私房菜-shell脚本-上
猫宁~~~ 建议全程在centos7中进行,我在kali linux中有些命令无法执行. 1~家目录下创建bin文件,test.sh文件在bin目录 下面的shell代码打印Hello World! ...