从诞生至今,20多年过去,Java至今仍是使用最为广泛的语言。这仰赖于Java提供的各种技术和特性,让开发人员能优雅的编写高效的程序。今天我们就来说说Java的一项基本但非常重要的技术内存管理

了解C语言的同学都知道,在C语言中内存的开辟和释放都是由我们自己来管理的,每一个new操作都要对于一个delete操作,否则就会参数内存泄漏和溢出的问题,导致非常槽糕的后果。但在Java开发过程中,则完全不需要担心这个问题。因为jvm提供了自动内存管理的机制。内存管理的工作由jvm帮我们完成。这样我们就不用为了释放内存而头疼了。

Jvm内存浅析

虽然jvm帮我们做了内存管理的工作,但是我们仍需要了解jvm到底做了什么,下面我们就一起去看一看

jvm启动时进行一系列的工作,其中一项就是开辟一块运行时内存。而这一块内存中又分为了五大区域,分别用于不同的功能。

程序计数器

记录程序运行的下一条指令的地址,这里的“地址”可以是一个本地指针,也可以是在方法字节码中相对于该方法起始指令的偏移量。如果该线程正在执行一个本地方法,那么此时程序计数器的值为”undefined”.在多线程环境下,每一个线程都有自己的程序计数器,在jvm调度线程时,会把当前的线程的程序计数器保存到快照,以便下次线程获取执行时间时获取

VM Stack

虚拟机栈是Java方法执行的内存模型,每个方法执行的时候,会在栈中创建一帧用于存储局部变量表、操作数栈、动态链接、方法出口。方法开始调用时,会创建栈帧并入栈,方法执行结束时会出栈。每个线程都有自己的栈。

动态链接:是一种在常量池中指向方法的符号引用,需要在运行期确定为直接引用

方法出口:当前执行方法的调用者的程序计数器,或异常处理表的地址

可以通过 -xxs 大小 来配置栈的大小,当嵌套调用使用不当,会导致方法不停的入栈,最终导致栈空间被占满产生 StackOverflowError

本地方法栈

Heap

堆是用于存放对象实例的地方,几乎所有对象实例在堆中分配。堆是线程共享的,这是多线程时同步机制的原因。

堆是GC管理的主要区域,GC在对堆进行回收前,首先要确定对象是否已死(不可能再被使用的对象)

判断对象是否存活的算法有两种:引用计数算法、可达性分析算法

引用计数算法是为每一个对象添加一个引用计数器,每当有一个引用指向它时,计数器就加一,任何时刻计数器为0的对象就不可能再被使用。这种算法实现简单,但是它很难解决对象循环引用的问题(何为循环引用见下方备注)

可达性分析算法是Java语言正在使用的算法。它的基本思想是通过一系统被称为“GC Root”的对象为起点,从这个起点向下搜索,搜索走过的路径称为引用链,当一个对象不再任何引用链上时,则说明这个对象是不可能再被使用的。

在Java语言中,GC Root包括以下几种对象:

  1. 虚拟机栈中引用的对象
  2. 本地方法栈中JNI引用的对象
  3. 方法区中类静态成员变量引用的对象
  4. 方法区中常量引用的对象

可以看出分析对象是否存活,都与引用有关。在JDK1.2之后,Java对引用的概念进行了扩充,将引用分为 强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference)

  1. 强引用

强引用即为原来意义上的引用,只要强引用存在,被引用的对象就不会被回收

  1. 软引用

SoftReference类表示软引用,对于被软引用关联的对象,在系统将要发生内存溢出时,会把这些对象列入回收范围后,进行二次回收

  1. 弱引用

WeakReference类表示弱引用,对于被弱引用关联的对象,只能生存到下一次垃圾回收发生之前

  1. 虚引用

PhantomReference类表示虚引用,虚引用不对关联的对象的生存时间构成影响,也无法取得对象实例,它唯一的作用是在对象被GC回收是收到一条系统通知

堆得大小可以通过-Xmx和-Xms来控制。对于主流的Jvm,GC基本都采用分代收集的算法。基于这个算法, Java堆又分为新生代(Young Generation)和老年代(Old Generation),新生代又被进一步划分为Eden和Survivor区,最后Survivor由FromSpace和ToSpace组成。新建的对象都是用新生代分配内存,Eden空间不足的时候,会把存活的对象转移到Survivor中,新生代大小可以由-Xmn来控制,也可以用-XX:SurvivorRatio来控制Eden和Survivor的比例。老生代用于存放新生代中经过多次垃圾回收(也即Minor GC)仍然存活的对象。

永生代(Permanent Space)为方法区

方法区

方法区也为所以线程所共享,用于存放已加载的类信息、静态变量、常量和即时编译器编译后的代码。-XX:MaxPermSize用于设置方法区大小

直接内存

直接内存不是虚拟机运行时数据区的一部分。通过Native函数库直接分配的堆外内存,然后通过存储在Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作

内存分配和回收策略

目前为止,jvm已经发展处三种比较成熟的垃圾收集算法:1.标记-清除算法;2.复制算法;3.标记-整理算法;4.分代收集算法

1.        标记-清除算法

这种垃圾回收一次回收分为两个阶段:标记、清除。首先标记所有需要回收的对象,在标记完成后回收所有被标记的对象。这种回收算法会产生大量不连续的内存碎片,当要频繁分配一个大对象时,jvm在新生代中找不到足够大的连续的内存块,会导致jvm频繁进行内存回收(目前有机制,对大对象,直接分配到老年代中)

2.        复制算法

这种算法会将内存划分为两个相等的块,每次只使用其中一块。当这块内存不够使用时,就将还存活的对象复制到另一块内存中,然后把这块内存一次清理掉。这样做的效率比较高,也避免了内存碎片。但是这样内存的可使用空间减半,是个不小的损失。

3.        标记-整理算法

这是标记-清除算法的升级版。在完成标记阶段后,不是直接对可回收对象进行清理,而是让存活对象向着一端移动,然后清理掉边界以外的内存

4.        分代收集算法

当前商业虚拟机都采用这种算法。首先根据对象存活周期的不同将内存分为几块即新生代、老年代,然后根据不同年代的特点,采用不同的收集算法。在新生代中,每次垃圾收集时都有大量对象死去,只有少量存活,所以选择了复制算法。而老年代中因为对象存活率比较高,所以采用标记-整理算法(或者标记-清除算法)

GC的执行机制

由于对象进行了分代处理,因此垃圾回收区域、时间也不一样。GC有两种类型:Scavenge GC和Full GC。

  Minor GC

  一般情况下,当新对象生成,并且在Eden申请空间失败时,就会触发Minor GC,对Eden区域进行GC,清除非存活对象,并且把尚且存活的对象移动到Survivor区。然后整理Survivor的两个区。这种方式的GC是对年轻代的Eden区进行,不会影响到年老代。因为大部分对象都是从Eden区开始的,同时Eden区不会分配的很大,所以Eden区的GC会频繁进行。因而,一般在这里需要使用速度快、效率高的算法,使Eden去能尽快空闲出来。

  Full GC

  对整个堆进行整理,包括Young、Tenured和Perm。Full GC因为需要对整个堆进行回收,所以比Minor GC要慢,因此应该尽可能减少Full GC的次数。在对JVM调优的过程中,很大一部分工作就是对于FullGC的调节。有如下原因可能导致Full GC:

  1.年老代(Tenured)被写满

  2.持久代(Perm)被写满

  3.System.gc()被显示调用

4.上一次GC之后Heap的各域分配策略动态变化

Java常见的内存泄漏

  1. 数据库连接,网络连接,IO连接等没有显示调用close关闭,会导致内存泄露
  2. 监听器的使用,在释放对象的同时没有相应删除监听器的时候也可能导致内存泄露

作者:南唐三少
出处:http://www.cnblogs.com/nantang

如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我们最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文链接,否则保留追究法律责任的权利。

Jvm 内存浅析 及 GC个人学习总结的更多相关文章

  1. 管中窥豹——从对象的生命周期梳理JVM内存结构、GC调优、类加载、AOP编程及性能监控

    如题,本文的宗旨既是透过对象的生命周期,来梳理JVM内存结构及GC相关知识,并辅以AOP及双亲委派机制原理,学习不仅仅是海绵式的吸收学习,还需要自己去分析why,加深对技术的理解和认知,祝大家早日走上 ...

  2. JVM内存模型及GC回收算法

    该篇博客主要对JVM内存模型以及GC回收算法以自己的理解和认识做以记录. 内存模型 GC垃圾回收 1.内存模型 从上图可以看出,JVM分为 方法区,虚拟机栈,本地方法栈,堆,计数器 5个区域.其中最为 ...

  3. JVM内存概览与GC初步

    一.JVM内存空间概览 Java虚拟机使用的内存块包含 栈空间Stack (虚拟机栈.本地方法栈).堆空间 Heap Memory .永久区 Perm Gen(related to method ar ...

  4. JVM内存模型与GC算法

    1.JVM内存模型 JVM内存模型如上图,需要声明一点,这是<Java虚拟机规范(Java SE 7版)>规定的内容,实际区域由各JVM自己实现,所以可能略有不同.以下对各区域进行简短说明 ...

  5. JVM内存模型和GC机制

    目录 1.JVM内存模型 2.GC 1.JVM内存模型 堆,栈,本地方法栈,方法区,程序计数器 2.GC 新生代收集器:Serial(单线程).ParNew.Parallel Scavenge: 老年 ...

  6. JVM内存管理及GC机制

    一.概述 Java GC(Garbage Collection,垃圾收集,垃圾回收)机制,是Java与C++/C的主要区别之一,作为Java开发者,一般不需要专门编写内存回收和垃圾清理代码,对内存泄露 ...

  7. JVM内存结构与GC

    JVM内存模型总体架构图 程序计数器多线程时,当线程数超过CPU数量或CPU内核数量,线程之间就要根据时间片轮询抢夺CPU时间资源.因此每个线程有要有一个独立的程序计数器,记录下一条要运行的指令.线程 ...

  8. JVM内存布局及GC知识回顾

    注:本文篇幅较长,且需要有一定的java基础,建议各位看官,备好瓜子.饮料.小板凳,摆个让自己舒服的姿势,慢慢细看^_^, 文中所有素材,均来自互联网,本人只是详细梳理了一遍,形成此文. 一.JVM运 ...

  9. JVM内存模型与GC算法(简介)

    JVM内存模型如上图,需要声明一点,这是<Java虚拟机规范(Java SE 7版)>规定的内容,实际区域由各JVM自己实现,所以可能略有不同.以下对各区域进行简短说明. 1.1程序计数器 ...

随机推荐

  1. C# 在腾讯的发展

    本文首发我的微信公众号"dotnet跨平台", 内容得到大家热烈的欢迎,全文重新发布在博客,欢迎转载,请注明出处. .NET 主要的开发语言是 C# , .NET 平台泛指遵循EC ...

  2. SDWebImage源码解读之SDWebImageDownloaderOperation

    第七篇 前言 本篇文章主要讲解下载操作的相关知识,SDWebImageDownloaderOperation的主要任务是把一张图片从服务器下载到内存中.下载数据并不难,如何对下载这一系列的任务进行设计 ...

  3. hash表长度优化证明

    hash表冲突的解决方法一般有两个方向: 一个是倾向于空间换时间,使用向量加链表可以最大程度的在节省空间的前提下解决冲突. 另外一个倾向于时间换空间,下面是关于这种思路的一种合适表长度的证明过程: 这 ...

  4. 在Ubuntu 16.10安装mysql workbench报未安装软件包 libpng12-0错误

    1.安装mysql workbench,提示未安装软件包 libpng12-0 下载了MySQL Workbench 6.3.8   在安装的时候报错: -1ubu1604-amd64.deb 提示: ...

  5. MVC Core 网站开发(Ninesky) 2.1、栏目的前台显示

    上次创建了栏目模型,这次主要做栏目的前台显示.涉及到数据存储层.业务逻辑层和Web层.用到了迁移,更新数据库和注入的一些内容. 一.添加数据存储层 1.添加Ninesky.DataLibrary(与上 ...

  6. Hawk 5.1 数据导入和导出

    除了一般的数据库导入导出,Hawk还支持从文件导入和导出,支持的文件类型包括: Excel CSV(逗号分割文本文件) TXT (制表符分割文本文件) Json xml Excel 目前来看,Exce ...

  7. dotNet Core开发环境搭建及简要说明

    一.安装 .NET Core SDK 在 Windows 上使用 .NET Core 的最佳途径:使用Visual Studio. 免费下载地址: Visual Studio Community 20 ...

  8. 在DevExpress程序中使用GridView直接录入数据的时候,增加列表选择的功能

    在我上篇随笔<在DevExpress程序中使用Winform分页控件直接录入数据并保存>中介绍了在GridView以及在其封装的分页控件上做数据的直接录入的处理,介绍情况下数据的保存和校验 ...

  9. Kafka:主要参数详解(转)

    原文地址:http://kafka.apache.org/documentation.html ############################# System ############### ...

  10. ASP.NET Core MVC 配置全局路由前缀

    前言 大家好,今天给大家介绍一个 ASP.NET Core MVC 的一个新特性,给全局路由添加统一前缀.严格说其实不算是新特性,不过是Core MVC特有的. 应用背景 不知道大家在做 Web Ap ...