Java的一些基础小知识之JVM与GC (转)

一、JVM是什么


Java虚拟机(英语:Java Virtual Machine,缩写为JVM),又名爪哇虚拟器,一种能够运行Java bytecode的虚拟机,以堆栈结构机器来进行实做。最早由太阳微系统所研发并实现第一个实现版本,是Java平台的一部份,能够运行以Java语言写作的软件程序。

Java虚拟机有自己完善的硬体架构,如处理器、堆栈、寄存器等,还具有相应的指令系统。JVM屏蔽了与具体操作系统平台相关的信息,使得Java程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。通过对中央处理器(CPU)所执行的软件实作,实现能执行编译过的Java程序码(Applet与应用程序)。

作为一种编程语言的虚拟机,实际上不只是专用于Java语言,只要生成的编译文件符合JVM对载入编译文件格式要求,任何语言都可以由JVM编译运行。除外,除了甲骨文,也有其他开源或闭源的实现。

——维基百科

这个描述还是很简单易懂的,虚拟机的这种机制带给了代码一种全新的生命力,就是一处编绎,到处运行。当然美好的事情总归是有些缺陷的。因为要在一台物理机器上搭建一套虚拟的体系,以此来解决各个硬件与系统间的差异问题,确实是件很美好的事情,但同时损失的自然就是运行时的效率。

二、JVM的体系规格

java的这套体系是种开放的规格,只要能按规格编绎出来的程序都可以跑在JVM上。JVM定义了控制Java代码解释执行和具体实现的五种规格,它们是:

  • JVM指令系统
  • JVM寄存器
  • JVM 栈结构
  • JVM 碎片回收堆
  • JVM 存储区

三、JVM的工作原理

  • 操作系统加载JVM(windows)

1.创建JVM装载环境和配置

2.装载JVM.dll

3.初始化JVM.dll并挂界到JNIENV(JNI调用接口)实例

4.调用JNIEnv实例装载并处理class类

  • JVM加载类

下面看看一个java代码是怎么运行起来的:

参考文:http://www.ibm.com/developerworks/cn/java/j-lo-classloader/

四、JVM的内存管理

这里有一篇文章讲的很详细:http://developer.51cto.com/art/201303/387175.htm

JVM的内存结构分为6块:PC Register(PC寄存器)、JVM堆、JVM栈、方法区域、运行时常量、本地方法堆栈。如下图示意:

对于开发来说主要关注的还是堆和栈。

JVM一些参数设置:

-Xss:这个参数就是用来指定栈的大小

-Xms:设置JVM启动时最小的堆内存大小

-Xmx:设置JVM堆的最大内存大小

-XX:PermSize及-XX:MaxPermSize指定方法区域(MethodArea)的初始值与最大值

MethodArea对应的是持久代(PermanetGeneration),所以设置Perm的大小很重要,否则会报java.lang.OutOfMemoryError: PermGen space。

五、垃圾收集器(Garbage Collector,GC)

垃圾收集器这个东西对于程序员来说可谓是一种解脱,可以不用显式释放内存了。这种神奇的疗效还是要看看他的基本原理了解一下情况才行。下面摘了一段话:

有几种垃圾收集的基本策略:引用计数、标记-清除、标记-整理 (mark-compact) 和复制。此外,一些算法可以以 增量 方式完成它们的工作(不需要一次收集整个堆,使得收集暂停时间更短),一些算法可以在用户程序运行时运行( 并发收集)。其他算法则必须在用户程序暂停时一次进行整个收集(即所谓的 stop-the-world收集器)。最后,还有混合型的收集器,如 1.2 和以后版本的 JDK 使用的分代收集器,它对堆的不同区域使用不同的收集算法。

——摘自developerWorks 中国

这里就回收的算法来看主要就上面列出来的几种,其中比较重要的是“复制”和“标识-整理”有必要理解一下。

复制收集器就是划分两个对等空间,其中一个放活跃对象,另一个空着,等第一个满了就复制活跃对象到另一个空着的,然后将这两个空间角色换一下。这里有个重点就是只复制活跃对象。活跃对象通常就是可到达的对象也就是不用回收的内存,换言之就是除此之外的就是垃圾,那么这样的好处就是复制一次后,将那些垃圾一次回收就行了。而且复制后内存空间是会经过整理的连续的,不会有碎片问题。

标识-整理收集器算法结合了标记-清除和复制,代价是增加了一些收集复杂性。与标记-清除类似,标记-整理是两阶段过程,在标记阶段访问并标记每个活跃对象。然后,复制标记的对象,使所有活跃对象被整理到堆的底部。如果每一次收集时进行彻底的整理,那么得到的堆就类似于复制收集器的结果 ―― 在堆的活跃部分与自由部分有明确的界线,这样分配成本与复制收集器相当。长寿的对象趋向于沉在堆的底部,这样就不会像在复制收集器中那样反复复制它们。

既然是垃圾回收,那么自然有一个问题什么是垃圾?


由分配器分配的,但是用户程序不可到达的内存块。不可到达是什么意思?可以以两种方式之一访问内存块 ―― 或者用户程序在 根 (root)中有对这一内存块的引用,或者在另一个可到达的块中有对这个块的引用。

——摘自developerworks

这里面提到了一个很关键的点,就是根(Root),那什么才是Root?这个得好好了解一下。下面是GC Root的种类:

  • Class - 由系统类加载器(system class loader)加载的对象,这些类是不能够被回收的,他们可以以静态字段的方式保存持有其它对象。我们需要注意的一点就是,通过用户自定义的类加载器加载的类,除非相应的java.lang.Class实例以其它的某种(或多种)方式成为roots,否则它们并不是roots,.
  • Thread - 活着的线程
  • Stack Local - Java方法的local变量或参数
  • JNI Local - JNI方法的local变量或参数
  • JNI Global - 全局JNI引用
  • Monitor Used - 用于同步的监控对象
  • Held by JVM - 用于JVM特殊目的由GC保留的对象,但实际上这个与JVM的实现是有关的。可能已知的一些类型是:系统类加载器、一些JVM知道的重要的异常类、一些用于处理异常的预分配对象以及一些自定义的类加载器等。然而,JVM并没有为这些对象提供其它的信息,因此就只有留给分析分员去确定哪些是属于"JVM持有"的了。

分代垃圾收集

有人做过分析,应用程序堆中的对象有98%的对象存活的时间比较短,还有一些是会存活很长,甚至会随着应用程序整个生命周期。将这两类对象可以称为年轻代和持久代。


分代收集器(generializational collector)将堆分为多个代。在年轻的代中创建对象,满足某些提升标准的对象,如经历了特定次数垃圾收集的对象,将被提升到下一更老的代。分代收集器对不同的代可以自由使用不同的收集策略,对各代分别进行垃圾收集。

——摘自developerworks

可以看出分代垃圾收集主要是将对象以生命周期进行归类,然后针对不同的类别使用不同的回收算法,这样就可以更优的进行跟踪回收。

JDK 1.4.1 默认收集器

在默认情况下,JDK 1.4.1 将堆分为两部分,一个年轻的代和一个老的代(实际上,还有第三部分――永久空间,它用于存储装载的类和方法对象)。借助于复制收集器,年轻的代又分为一个创建空间(通常称为 Eden)和两个生存半空间。

老的代使用标记-整理收集器。对象在经历了几次复制后提升到老的代。小的收集将活的对象从 Eden 和一个生存半空间复制到另一个生存半空间,并可能提升一些对象到老的代。大的收集(major collection)既会收集年轻的代,也会收集老的代。 System.gc() 方法总是触发一个大的收集,这就是应该尽量少用(如果不能完全不用的话) System.gc() 的原因之一,因为大的收集要比小的收集花费长得多的时间。没有办法以编程方式触发小的收集。

——摘自developerworks

总的机制就是让寿命长的对象逐步往老的代中放,这样可以优化收集的时机,减少收集暂停给应用程序带来的影响。基本上GC的简单机制就这些内容。

参考文:

http://blog.csdn.net/java2000_wl/article/details/8022293

http://www.ibm.com/developerworks/cn/java/j-jtp11253/

http://www.cnblogs.com/5207/p/4275882.html

时间: 2024-10-12 09:14:59

Java的一些基础小知识之JVM与GC (转)的相关文章

学习笔记:Java的一些基础小知识之JVM与GC

一.JVM是什么 Java虚拟机(英语:Java Virtual Machine,缩写为JVM),又名爪哇虚拟器,一种能够运行Java bytecode的虚拟机,以堆栈结构机器来进行实做.最早由太阳微系统所研发并实现第一个实现版本,是Java平台的一部份,能够运行以Java语言写作的软件程序. Java虚拟机有自己完善的硬体架构,如处理器.堆栈.寄存器等,还具有相应的指令系统.JVM屏蔽了与具体操作系统平台相关的信息,使得Java程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多

Java基础小知识(一)

 序言:“不积跬步,无以至千里.不积小流,无以成江海.”每一个庞大的知识架构都是由无数个小知识点慢慢积累起来的,没有量变的积累,就没有质变上的飞跃,成功往往离不开积累. 今天就和大家分享一些我在学习JAVA过程中总结的一些小知识吧! ①JAVA语言规定标识符的命名规则: 标识符应以“字母”.“下划线”.“美元符号$” 开头,不能以“数字”开头: 标识符可以由“字母(A-Z,a-z)”.“下划线”.“美元符号$” 或“数字(0-9)”组成: Java标识符需要注意区分大小写,长度无限制:(类名首字

基础小知识,持续更新中~

一.一些基础小命令 dir = 查看当前目录文件列表 cd .. 返回上一层目录 cd ../.. 返回上上一层目录 二.关于中文编码 #-*- coding:utf-8 -*-print ("中国") 三.设置notepad++ 快捷键 设置--->首选项--->语言---->勾选替换为空格,tab键自动打印4个空格 视图--->显示符号--->显示空格与制表符. 四.注释 # 单行注释'''多行注释'''""" 多行注释

Java 基础小知识 (随学习不断补充)

最近希望巩固一下基础,看了李兴华老师的<Java核心技术精讲>一书,随着学习过程记录整理一下一些零散的小知识点,方便以后记忆. 如有错误和建议,欢迎指出. 1.Java中的关键字 abstract assert boolean break byte case catch char class continue const default do double else extends enum final finally float for goto if implements import i

java基础小知识

1.1常量: 基本数据类型常量 字符常量 整数常量的表现形式:一进制的形式来表示(二进制,八进制,十进制,十六进制) 生活中:十进制(0-9)  ,星期(七进制(0-6)) ,时间(十二进制(0-11),二十四进制(0-23)) 计算机是通过二进制来读取我们生活中的数据. 进制之间的转换: 十进制转为二进制: 将十进制除以2,直到商为0 ,将余数从下上连接起来就是二进制 10---->1010 二进制转十进制:将二进制的每一位乘以2^n ,n从0开始,n每一次加一,在将结果相加. 1001 --

android&quot;百码&quot;2——基础小知识积累(逐步完善)2015-06-15

自己对java基础知识.语法.基本数据类型等方面都不是很掌握,经常在一些很基础的问题上折腾好一段时间,最近在执行“百码”计划,因此专门写一篇博文用于记录日常编程过程中遇到的一些薄弱知识点,逐个积累起来,填补自己的薄弱环节. 1.Spinner设置默认值 在对spinner设置完数据适配器后,系统默认将数据源的第一个数据作为spinner默认值,很多时候我们需要自定义这个默认值,或者说我们需要通过代码的方式去控制spinner当前值,这时候就需要用到setSelection()函数,使用代码如下:

前端基础小知识

CSS布局 布局是CSS中一个重要部分,本文总结了CSS布局中的常用技巧,包括常用的水平居中.垂直居中方法,以及单列布局.多列布局的多种实现方式(包括传统的盒模型布局和比较新的flex布局实现),希望能给需要的小伙伴带来一些帮助. 目录 1.常用居中方法:水平居中,垂直居中, 2.单列布局 3.二列&三列布局:float+margin,position+margin,圣杯布局(float+负margin),双飞翼布局(float+负margin),flex布局 如果你想学习交流html5css3

java中方法传值小知识解析

1.java语言参数之间只有值传递,包括按值调用和按引用调用. 一个方法可以修改传递引用所对应的变量值,而不能修改传递值调用所对应的变量值. 按值调用:包括八大基本数据类型都是按值调用.传值的时候,也就是说方法得到的是所有参数值的一个拷贝. 按引用调用:数组.对象.传值时候,传递的是引用地址的拷贝,但是都是指向同一个对象. 2.String是不可变类(final and Immutable) 下面给大家一个例子: public class Example{     String str=new

tomcat基础小知识

tomcat目录\bin下: .bat文件和.sh文件用于在window系统和linux等其他系统执行. 1startup.bat 和 shutdown.bat 启动和关闭tomcat. 2version.bat查看tomcat目录,jdk版本,当前操作系统等. 以windows系统为例,编辑 version.bat,在末尾加上pause,双击运行 tomcat目录\conf下: server.xml用于更改发布地址和端口 tomcat目录\webapps: 放需要发布的程序,供访问. 查看端口