深入java虚拟机阅读笔记(jvm内存原理、异常处理部分)

深入理解Java虚拟机:JVM高级特性与最佳实践

阅读笔记(内存原理、异常处理):

1.    
Jvm运行时,内存划分如图所示:

2.    
程序计数器:

Jvm将这个计数看作当前线程执行某条字节码的行数,会根据计数器的值来选取需要执行的操作语句。这个属于线程私有,不可共享,如果共享会导致计数混乱,无法准确的执行当前线程需要执行的语句。

该区域不会出现任何OutOfMemoryError的情况。

3.    
虚拟机栈

经常说到的栈内存就是指虚拟机栈。Java中每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。

如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;如果虚拟机栈可以动态扩展(当前大部分的Java虚拟机都可动态扩展,只不过Java虚拟机规范中也允许固定长度的虚拟机栈),如果扩展时无法申请到足够的内存,就会抛出OutOfMemoryError异常。

4.    
本地方法栈

虚拟机栈用来执行java方法,而本地方法栈用来执行本地方法。

抛出异常的情况和虚拟机栈一样。

5.    

是jvm中内存最大、线程共享的一块区域。唯一的目的是存储对象实例。这里也是垃圾收集器主要收集的区域。由于现代垃圾收集器都采用的是分代收集算法,所以java堆也分为新生代和老年代。

可以通过参数-Xmx(jvm最大可用内存)和-Xms(jvm初始内存)来调整堆内存,如果扩大至无法继续扩展时,会出现OutOfMemoryError的错误。

6.    
方法区

Jvm中内存共享的一片区域,用来存储类信息、常量、静态变量、class文件。垃圾收集器也会对这部分区域进行回收,比如常量池的清理和类型的卸载,但是效果不理想。

方法区内存不够用的时候,也会抛出OutOfMemoryError错误。

7.    
对象创建

虚拟机遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有,那必须先执行相应的类加载过程,加载检查之后会在堆中划分出一定的内存。

在完成new指令之后,紧接着会调用<init>方法将对象初始化,这时一个完整的对象才算创建了出来。

8.    
对象的访问

在sun的jdk中采用的是指针访问方式,在reference中直接存储了对象的地址。

9.    
OutOfMemoryError错误

Java堆内存的OutOfMemoryError异常是实际应用中常见的内存溢出异常情况。当出现Java堆内存溢出时,异常堆栈信息“java.lang.OutOfMemoryError”会跟着进一步提示“Java heap space”。

当产生的对象过多时,会出现这个错误信息。解决办法:调整虚拟机堆参数(-Xmx和-Xms)。

Java方法区会存储类信息、常量、静态变量等。如果产生了大量类,比如某个ssh项目因为加载了框架和大量jar包,这样class文件都会载入内存的方法区,这样如果出现内存无法继续扩展的情况,也会出现java.lang.OutOfMemoryError,然后紧跟着PermGen
space信息。通过-XX:PermSize和-XX:MaxPermSize可以限制方法区大小。

10.  StackOverflow错误

Java中栈内存溢出,通常是由于栈深度超过限制深度,导致出现该问题。很常见的情况是,使用递归的时候,不小心忘了指定递归结束的时刻,导致递归深度超过限制深度,出现栈内存溢出。

11.  判断对象是否存活的算法

主流jvm虚拟机不会采用引用计数法,因为有种情况它无法判断是否存活。比如互成环路的几个对象,没有其他对象引用他们了,这样按道理来说是死对象,可以被回收,但是按照引用计数法的判定,他们计数还不为0,也就是还不能被回收。

主流商用jvm目前采用的是可达性算法。利用有向图的原理,从根节点(原点)GC ROOT可达的所有其他节点表示目前仍然被引用,无法被回收。而从它无法达到的对象节点(距离为∞)则表示该对象可以被回收。GC ROOT表示虚拟机栈中引用指向的对象或者方法区中的常量对象和静态对象,或者jni(java本地方法)中引用的对象。

12.  引用

引用代表的是数据A中存储了一个地址,这个地址指向另一快内存的起始地址,这个A就是一个引用。

强引用:无论何时都不会被回收。普遍存在,如Object o=new Object();

弱引用:当垃圾收集器工作时,就会回收弱引用指向的对象。

13.  回收流程

回收时系统会执行System.gc(),找到不可达对象,标记该对象为待回收对象,并查看该对象是否覆盖finalize()方法,如果覆盖了并且该方法之前没有被调用过,然后将他放到一个队列中,排着长队等着finalize()回收。即使进入finalize()方法,也不能保证该方法可以回收对象,因为对象可以在该方法里面关联其他引用,完成自救。综合而言,finalize()每次执行消耗成本高,但不能保证回收对象,所以效果并不好,并不推荐手动调用finalize()方法。

14.  垃圾收集算法

主流jvm都采用分代收集算法(将java堆分而治之):

新生代:大量对象死亡,少量存活,采用复制算法

java堆分成

老年代:少量死亡,大量存活,采用标记整理法或标记清除法

复制算法:将内存划分为两片区域A和B,每次都只占用A部分。这样A放了所有对象,B空着。每次收集的时候标记A中的存活部分,复制到B中,然后统一清除A中的内容即可。缺点:内存占用高!适用:新生代。

标记清除算法:标记所有垃圾对象,完成标记后统一清除这些垃圾对象。缺点:效率低,产生碎片多。适用:老年代。

标记整理算法:标记所有垃圾对象,将存活对象移动到一边,清掉另一边的垃圾对象。适用:老年代。

时间: 2024-10-05 05:00:26

深入java虚拟机阅读笔记(jvm内存原理、异常处理部分)的相关文章

深入理解java虚拟机读书笔记1--java内存区域

Java在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途.创建和销毁的时间,有一些是随虚拟机的启动而创建,随虚拟机的退出而销毁,有些则是与线程一一对应,随线程的开始和结束而创建和销毁. Java虚拟机所管理的内存将会包括以下几个运行时数据区域: 1 程序计数器 它是一块较小的内存空间,它的作用可以看做是当先线程所执行的字节码的信号指示器. java虚拟机的多线程是通过轮流切换并分配处理器执行时间的方式来实现的,在任何一个确定的时刻,一个处理器(对于多

[深入理解Java虚拟机]&lt;阅读笔记&gt;

Overview 走近Java:介绍Java发展史 第二部分:自动内存管理机制 程序员把内存控制的权利交给了Java虚拟机,从而可以在编码时享受自动内存管理.但另一方面一旦出现内存泄漏和溢出等问题,就需要了解一些底层的知识来进行错误排查. 自动内存管理机制:介绍内存是如何划分的. 垃圾收集器与内存分配策略:分析垃圾收集算法. 虚拟机性能监控与故障处理工具 调优案例分析与实战 第三部分:虚拟机执行子系统 类文件系统:介绍Class文件结构的各个组成部分. 虚拟机类加载机制:介绍类加载过程的各个阶段

深入理解Java 虚拟机阅读笔记(一)

1.程序计数器- 占用空间:较小 作用:字节码行号指示器 作用详情:指示指令执行,如(字节码的执行,分支,循环,跳转,异常处理,线程恢复) 特点:线程私有(每个计数器独立计算,上下文相互独立). 2.虚拟机栈 占用空间:依据栈空间设定 作用:java 方法执行的内存模型. 作用详情:每个方法执行时都会创建栈桢.用于储存局部变量表.栈操作数.动态链接.方法出口等信息.每个方法从调用到执行完成就对应一个栈帧在虚拟机栈中入栈到出栈的过程 特点:线程私有 3.本地方法栈 本地方法栈(Native Met

深度理解java虚拟机读书笔记(二)HotSpot Java对象创建,内存布局以及访问方式

内存中对象的创建.对象的结构以及访问方式. 一.对象的创建 在语言层面上,对象的创建只不过是一个new关键字而已,那么在虚拟机中又是一个怎样的过程呢? (一)判断类是否加载.虚拟机遇到一条new指令的时候,首先会检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号代表的类是否被加载.解析并初始化.如果没有完成这个过程,则必须执行相应类的加载. (二)在堆上为对象分配空间.对象需要的空间大小在类加载完成后便能确定.之后便是在堆上为该对象分配固定大小的空间.分配的方式也有两种:

《深入理解Java虚拟机》笔记02:Java内存区域与内存溢出异常

1.运行时数据区域 Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途,以及创建和销毁的时间: 有的区域随着虚拟机进程的启动而存在 有些区域则依赖用户线程的启动和结束而建立和销毁 根据<Java虚拟机规范(Java SE 7版)>的规定,Java虚拟机所管理的内存将会包括以下几个运行时数据区域,如图所示. 1.1 程序计数器 程序计数器(Program Counter Register)是一块较小的内存空间,它可以看作是当前线程所执行的

Java虚拟机解析篇之---内存模型

今天闲来无事来,看一下Java中的内存模型和垃圾回收机制的原理.关于这个方面的知识,网上已经有非常多现成的资料能够供我们參考,可是知识还是比較杂的,在这部分知识点中有一本书不得不推荐:<深入理解Java虚拟机>,如今已经是第二版了.这本书就从头開始详细介绍了Java整个虚拟机的模型以及Java的类文件结构,载入机制等.这里大部分的知识点都是能够在这本书中找到的,当然我是主要还是借鉴这本书中的非常多内容的.以下就不多说了.进入主题吧. 首先来看一下Java中的内存模型图: 第一.程序计数器(PC

Java虚拟机详解——JVM常见问题总结

[正文] 声明:本文只是做一个总结,有关jvm的详细知识可以参考之前的系列文章,尤其是那篇:Java虚拟机详解04--GC算法和种类.那篇文章和本文是面试时的重点. 面试必问关键词:JVM垃圾回收.类加载机制. 先把本文的目录画一个思维导图:(图的源文件在本文末尾) 一.Java引用的四种状态: 强引用:  用的最广.我们平时写代码时,new一个Object存放在堆内存,然后用一个引用指向它,这就是强引用. * 如果一个对象具有强引用,那垃圾回收器绝不会回收它*.当内存空间不足,Java虚拟机宁

《深入Java虚拟机学习笔记》- 第7章 类型的生命周期

一.类型生命周期的开始 如图所示 初始化时机 所有Java虚拟机实现必须在每个类或接口首次主动使用时初始化: 以下几种情形符合主动使用的要求: 当创建某个类的新实例时(或者通过在字节码中执行new指令,或者通过不明确的创建.反射.克隆和反序列化): 当调用某个类的静态方法时(即在字节码中执行invokestatic指令): 当使用某个类或接口的静态字段,或者对该字段赋值时(用final修饰的静态字段除外,它被初始化为一个编译时常量表达式): 当调用Java API中的某些反射方法: 当初始化某个

Java虚拟机垃圾收集器与内存分配策略

Java虚拟机垃圾收集器与内存分配策略 概述 那些内存需要回收,什么时候回收,如何回收是GC需要完成的3件事情. 程序计数器,虚拟机栈与本地方法栈这三个区域都是线程私有的,内存的分配与回收都具有确定性,内存随着方法结束或者线程结束就回收了. java堆与方法区在运行期才知道创建那些对象,这部分内存分配是动态的,本章笔记中分配与回收的内存指的就是:java堆与方法区. 判断对象已经死了 引用计数算法:给对象添加一个引用计数器,每当有一个地方引用它,计数器+1;引用失败,计数器-1.计数器为0则改判