`

jvm学习笔记

    博客分类:
  • java
 
阅读更多

##1.Jvm运行期实例负责运行java程序,但java程序启动时便创建了一个jvm实例,当程序结束时,该实例也消失. 一般,JVM的内存分为两部分:Stack和Heap。

##2.栈stack是解决程序运行问题,代表逻辑,堆heap解决数据的存储问题,代表数据。一个线程都有一个线程栈对应,而堆可以被多个栈共享.

##3.堆中存的是对象。栈中存的是基本数据类型堆中对象的引用

##4。一般,JVM的内存分为两部分:Stack和Heap。程序永远都是在栈stack中运行的.

###4.JVM调优的最基本的方向是怎样回收垃圾(不使用的对象)才有效并且节省空间.

###5.垃圾回收是从哪里开始的? 因为程序是在栈中执行的,所以要知道哪些对象被使用,则需要从栈stack开始,这样以栈中的引用为起点,可以找到对应的堆中的对象,从这个对象又可以找到堆中其他被引用的对象,这种引用逐步展开,这样形成一颗以java栈中引用所对应的对象为根节点的对象树,如果栈中有多个引用便存在多个对象树,这些对象树上的对象都是当前系统运行需要的对象,不能被回收,而堆中其他剩余的对象可以视为无法被引用的对象,可以当作垃圾进行回收。---〉以下所说的回收策略在标记清除和标记整理都是从根节点开始遍历标记的.

 

同时,除了栈外,还有系统运行时的寄存器等,也是存储程序运行数据的。这样,以栈或寄存器中的引用为

 

起点,我们可以找到堆中的对象,又从这些对象找到对堆中其他对象的引用,这种引用逐步扩展,最终以null引

 

用或者基本类型结束,这样就形成了一颗以Java栈中引用所对应的对象为根节点的一颗对象树,如果栈中有多

 

个引用,则最终会形成多颗对象树。在这些对象树上的对象,都是当前系统运行所需要的对象,不能被垃圾回

 

收。而其他剩余对象,则可以视为无法被引用到的对象,可以被当做垃圾进行回收。

 

因此,

 

垃圾回收的起点是一些根对象(java栈, 静态变量, 寄存器...)。而最简单的Java栈就是Java程序执行的

main函数。这种回收方式,也是上面提到的“标记-清除”的回收方式

 

 

---->接下来要问的是什么时候开始垃圾回收?在介绍完垃圾回收算法法后再说。

 ##6.垃圾回收算法 :

  $1.按回收策略分有:

   引用计数(引用就加1,删除一个引用就减1,最后回收0计数的)但无法处理循环引用问题。

   标记清除:从根节点开始第一次遍历先标记那些对象被引用,第二次遍历整个堆就删除没有被引用的. 需暂停整个应用,并会有碎片

   复制:使用双倍空间,将正在被引用的复制到另一空间,但需要两倍空间。

 

 

   标记整理: mark-compact, 也就是第一次遍历整个堆时,便标记哪个对象还被引用,然后第二次遍历堆时,便把未标记的对象清除(清理垃圾),同时把存活的对象压缩整理到堆的一块,这样便没有碎片.

 

 $2〉按系统线程分:

  串行收集(serial collector)使用单线程收集

  并行收集(parallel Collector)使用多线程

  并发收集(Concurrent Collector)无需暂停整个应用,上面两个要暂停.

 

$3)按分区对待的方式分 有增量收集和分代收集(上面那个两个不同角度的策略可以用到具体每个去上?---觉得三种可以结合起来用,只是角度和关注点不同: 比如在做选择时可以使用串行收集,也分代,那么在年轻代的收集时可以使用标记整理策略)

   分代收集依据是因为不同对象有不同的生命周期,所以就可以

把不同生命周期的对象放在不同代上(不同的分区上),不同代上采用最适合它的垃圾回收方式进行回收.

  如果不进行分代(分区)的话,每次垃圾回收都需要对整个堆空间进行遍历回收,那么花费时间会很长,在分代后,持久区基本没用遍历,其次是老年区也会做,主要是在年轻代做垃圾回收。

 #2.

虚拟机中的共划分为三个代:

年轻代(Young Generation)、年老代(Old Generation)和持久代

(Permanent Generation)

。其中持久代主要存放的是Java类的类信息,与垃圾收集要收集的Java对象关系

不大。年轻代和年老代的划分是对垃圾收集影响比较大的。

年轻代:

 

所有新生成的对象首先都是放在年轻代的。年轻代的目标就是尽可能快速的收集掉那些生命周期短的对象。

年轻代分三个区。一个Eden区,两个Survivor区(一般而言)。大部分对象在Eden区中生成。当Eden区满时,还存活的对象将被复制到Survivor区(两个中的一个),当这个Survivor区满时,此区的存活对象将被复制到另外一个Survivor区,当这个Survivor去也满了的时候,从第一个Survivor区复制过来的并且此时还存活的对象,将被复制“年老区(Tenured)”。需要注意,Survivor的两个区是对称的,没先后关系,所以同一个区中可能同时存在从Eden复制过来 对象,和从前一个Survivor复制过来的对象,而复制到年老区的只有从第一个Survivor去过来的对象。而且,Survivor区总有一个是空的。同时,根据程序需要,Survivor区是可以配置为多个的(多于两个),这样可以增加对象在年轻代中的存在时间,减少被放到年老代的可能。

年老代:

  在年轻代中经历了N次垃圾回收后仍然存活的对象,就会被放到年老代中。因此,可以认为年老代中存放的

 

都是一些生命周期较长的对象。

 

持久代:

 

用于存放静态文件,如今Java类、方法等。和生命比较长的对象,如Session对象持久代对垃圾回收没有显著影响,但是有些应用可能动态生成或

者调用一些class,例如Hibernate等,在这种时候需要设置一个比较大的持久代空间来存放这些运行过程中新

增的类。持久代大小通过-XX:MaxPermSize=<N>进行设置。

###3>什么情况下触发垃圾回收

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

Scavenge GCFull GC.

Scavenge GC:

 

  

 

 

 

 

一般情况下,当新对象生成,并且在Eden申请空间失败时,就会触发Scavenge GC,对Eden区域进行GC,

 

 

 

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

 

出来。

 

Full GC.:

 

 

 

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

 

 

 

年老代(Tenured)被写满

 
 

持久代(Perm)被写满

 

 

System.gc()被显示调用


###至于在调优时需要考虑用串行或者并行或者并发算法,已经配置堆的空间,每个代的空间等都可以通过设置参数来实现,详情可参考jvm调优.

调优工具可以用jconsole(jdk自带的)

 

###2。转自:http://developer.51cto.com/art/201003/188753.htm

 

深入Java虚拟机:JVM中的Stack和Heap

 

 

 

2010-03-15 14:24 joezheng123 JavaEye 字号:T | T
一键收藏,随时查看,分享好友!

 

 

 

在JVM中,静态属性保存在Stack指令内存区,动态属性保存在Heap数据内存区。本文将从JVM的角度来讲解Java虚拟机的这一机制。

 

在JVM中,内存分为两个部分,Stack(栈)和Heap(堆),这里,我们从JVM的内存管理原理的角度来认识Stack和Heap,并通过这些原理认清Java中静态方法和静态属性的问题。

一般,JVM的内存分为两部分:Stack和Heap。

Stack(栈)是JVM的内存指令区。Stack管理很简单,push一定长度字节的数据或者指令,Stack指针压栈相应的字节位移;pop一定字节长度数据或者指令,Stack指针弹栈。Stack的速度很快,管理很简单,并且每次操作的数据或者指令字节长度是已知的。所以Java 基本数据类型,Java 指令代码,常量都保存在Stack中。

Heap(堆)是JVM的内存数据区。Heap 的管理很复杂,每次分配不定长的内存空间,专门用来保存对象的实例。在Heap 中分配一定的内存来保存对象实例,实际上也只是保存对象实例的属性值,属性的类型和对象本身的类型标记等,并不保存对象的方法(方法是指令,保存在Stack中),在Heap 中分配一定的内存保存对象实例和对象的序列化比较类似。而对象实例在Heap 中分配好以后,需要在Stack中保存一个4字节的Heap 内存地址,用来定位该对象实例在Heap 中的位置,便于找到该对象实例。

由于Stack的内存管理是顺序分配的,而且定长,不存在内存回收问题;而Heap 则是随机分配内存,不定长度,存在内存分配和回收的问题;因此在JVM中另有一个GC进程,定期扫描Heap ,它根据Stack中保存的4字节对象地址扫描Heap ,定位Heap 中这些对象,进行一些优化(例如合并空闲内存块什么的),并且假设Heap 中没有扫描到的区域都是空闲的,统统refresh(实际上是把Stack中丢失了对象地址的无用对象清除了),这就是垃圾收集的过程;关于垃圾收集的更深入讲解请参考51CTO之前的文章《JVM内存模型及垃圾收集策略解析》。

JVM的体系结构
JVM的体系结构

我们首先要搞清楚的是什么是数据以及什么是指令。然后要搞清楚对象的方法和对象的属性分别保存在哪里。

1)方法本身是指令的操作码部分,保存在Stack中;

2)方法内部变量作为指令的操作数部分,跟在指令的操作码之后,保存在Stack中(实际上是简单类型保存在Stack中,对象类型在Stack中保存地址,在Heap 中保存值);上述的指令操作码和指令操作数构成了完整的Java 指令。

3)对象实例包括其属性值作为数据,保存在数据区Heap 中。

非静态的对象属性作为对象实例的一部分保存在Heap 中,而对象实例必须通过Stack中保存的地址指针才能访问到。因此能否访问到对象实例以及它的非静态属性值完全取决于能否获得对象实例在Stack中的地址指针。

非静态方法和静态方法的区别:

非静态方法有一个和静态方法很重大的不同:非静态方法有一个隐含的传入参数,该参数是JVM给它的,和我们怎么写代码无关,这个隐含的参数就是对象实例在Stack中的地址指针。因此非静态方法(在Stack中的指令代码)总是可以找到自己的专用数据(在Heap 中的对象属性值)。当然非静态方法也必须获得该隐含参数,因此非静态方法在调用前,必须先new一个对象实例,获得Stack中的地址指针,否则JVM将无法将隐含参数传给非静态方法。

静态方法无此隐含参数,因此也不需要new对象,只要class文件被ClassLoader load进入JVM的Stack,该静态方法即可被调用。当然此时静态方法是存取不到Heap 中的对象属性的。

总结一下该过程:当一个class文件被ClassLoader load进入JVM后,方法指令保存在Stack中,此时Heap 区没有数据。然后程序技术器开始执行指令,如果是静态方法,直接依次执行指令代码,当然此时指令代码是不能访问Heap 数据区的;如果是非静态方法,由于隐含参数没有值,会报错。因此在非静态方法执行前,要先new对象,在Heap 中分配数据,并把Stack中的地址指针交给非静态方法,这样程序技术器依次执行指令,而指令代码此时能够访问到Heap 数据区了。

静态属性和动态属性

前面提到对象实例以及动态属性都是保存在Heap 中的,而Heap 必须通过Stack中的地址指针才能够被指令(类的方法)访问到。因此可以推断出:静态属性是保存在Stack中的,而不同于动态属性保存在Heap 中。正因为都是在Stack中,而Stack中指令和数据都是定长的,因此很容易算出偏移量,也因此不管什么指令(类的方法),都可以访问到类的静态属性。也正因为静态属性被保存在Stack中,所以具有了全局属性。

在JVM中,静态属性保存在Stack指令内存区,动态属性保存在Heap数据内存区。

 

 

 

分享到:
评论

相关推荐

    JVM学习笔记(一)

    ### JVM学习笔记(一) #### 一、JVM概述与工具使用 JVM(Java Virtual Machine)是Java语言的核心组成部分之一,它为Java程序提供了一个跨平台的运行环境。本篇学习笔记主要介绍如何利用一系列工具来查看和监控JVM...

    java之jvm学习笔记五(实践写自己的类装载器)

    这个“java之jvm学习笔记五(实践写自己的类装载器)”很可能是对这一主题的详细探讨。 类装载器在Java中的主要职责是动态加载类到JVM中。Java的类装载器分为三个基本层次:启动类装载器(Bootstrap ClassLoader)、...

    JVM学习笔记

    ### JVM学习笔记 #### JVM内存模型 (JMM) JVM内存模型主要分为以下几个部分: - **Java堆**:这是所有线程共享的一块区域,在虚拟机启动时创建。主要用于存放对象实例,几乎所有的对象实例都在这里分配内存。 - *...

    JVM学习笔记.docx

    本篇JVM学习笔记主要涵盖了以下几个核心知识点: 1. **运行时数据区**: - **程序计数器**:记录当前线程执行的字节码的行号,用于线程恢复执行时跳转到正确位置。 - **Java虚拟机栈**:每个方法执行时创建的栈帧...

    java之jvm学习笔记十一(访问控制器)-源码

    本文将深入探讨JVM中的访问控制器,主要基于“java之jvm学习笔记十一(访问控制器)-源码”这一主题,以及相关的源码分析。 首先,我们得了解Java的安全模型。Java安全模型基于一种称为安全管理器(SecurityManager)...

    JVM学习笔记(缓慢更新).md

    JVM学习笔记(缓慢更新).md

    JVM学习笔记2018-4-151

    本篇JVM学习笔记主要关注对象声明、相关内存分配方法以及虚拟内存的物理和虚拟寻址概念。 首先,我们来看对象声明。在Java中,对象是在堆上创建的。例如,`CHeapObj` 类展示了如何在C++中模拟Java对象在堆上的分配...

    JVM 学习笔记(Java虚拟机)

    **JVM学习笔记(Java虚拟机)** Java虚拟机(JVM)是Java语言的核心组成部分,它是Java程序运行的平台,负责解释和执行字节码。深入理解JVM对于优化Java应用程序性能至关重要。本笔记将从以下几个方面详细介绍JVM:...

    JVM学习笔记核心知识点整理

    ### JVM学习笔记核心知识点整理 #### 一、引言与背景 随着软件开发技术的不断发展,Java作为一种广泛应用的编程语言,其背后的核心技术——Java虚拟机(JVM)的重要性日益凸显。掌握JVM不仅可以帮助开发者更好地理解...

    java之jvm学习笔记十一(访问控制器) -源码

    本文将深入探讨JVM中的访问控制器,并通过分析"java之jvm学习笔记十一(访问控制器) -源码"中的`MySecurityManager`来进一步理解其工作原理。 访问控制器的主要任务是对类、方法和字段的访问进行限制,防止恶意代码...

    Java8 Jdk JVM学习笔记、jdk1.8、SpringBoot、内存与垃圾回收、类加载子系统、运行时数据区、本地方法等

    Java8 Jdk JVM学习笔记、jdk1.8、SpringBoot; 主要内容为 JVM 内存与垃圾回收、类加载子系统、运行时数据区、本地方法等。适合开发1-3年想对JVM学习的同学。 在之后的开发中,更加详细的了解JVM,可以进行JVM问题...

    jVM学习笔记.ppt

    JVM的学习可以从其基本结构、代码编译和执行过程,以及内存管理和垃圾回收机制三个方面进行深入探讨。 首先,JVM的基本结构分为逻辑结构和物理结构。逻辑结构主要包括Java源码编译器、JVM执行引擎、类加载器等组件...

    jvm学习笔记.zip

    《深入理解JVM:垃圾回收与优化》 在Java编程领域,JVM(Java Virtual Machine)扮演着至关重要的角色,它是Java程序...开发者需要不断学习和实践,才能在实际项目中有效地配置和优化JVM,确保程序的高效稳定运行。

    JVM 学习笔记

    NULL 博文链接:https://cooldatabase.iteye.com/blog/634599

    jvm学习笔记(jvm内存模型&垃圾收集算法&类加载机制)

    在JVM的学习中,理解其内存模型、垃圾收集算法以及类加载机制至关重要。 1. **JVM内存模型** - **方法区**:也称为“永久代”,存储虚拟机加载的类信息、常量、静态变量等,是线程共享的区域。在Java 8之后,这...

    java之jvm学习笔记八(实践对jar包的代码签名)

    Java的JVM(Java Virtual Machine)是Java程序运行的基础,它负责解释和执行字节码。在实际开发中,为了确保代码的安全性、完整性和防止恶意篡改,我们需要对Java的JAR(Java Archive)包进行代码签名。本文将深入...

    java之jvm学习笔记九(策略文件)

    在JVM的学习过程中,策略文件是一个重要的环节,它主要用于安全管理,控制不同代码的权限。本篇笔记将深入探讨Java策略文件的概念、结构以及如何使用。 策略文件是Java安全模型的一部分,它定义了哪些代码可以执行...

    java之jvm学习笔记十二(访问控制器的栈校验机制)

    本篇学习笔记将深入探讨这一主题,主要关注Java字节码的执行过程以及如何通过栈校验来防止非法操作。 Java字节码是由Java编译器生成的中间代码,它在JVM上运行前会经过类加载器的验证,其中栈校验是验证的一部分。...

Global site tag (gtag.js) - Google Analytics