一、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代码是怎么运行起来的:

 
四、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的简单机制就这些内容。
 
参考文:
 

学习笔记:Java的一些基础小知识之JVM与GC的更多相关文章

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

    一.JVM是什么 Java虚拟机(英语:Java Virtual Machine,缩写为JVM),又名爪哇虚拟器,一种能够运行Java bytecode的虚拟机,以堆栈结构机器来进行实做.最早由太阳微 ...

  2. 大数据学习笔记——Java篇之基础知识

    Java / 计算机基础知识整理 在进行知识梳理同时也是个人的第一篇技术博客之前,首先祝贺一下,经历了一年左右的学习,从完完全全的计算机小白,现在终于可以做一些产出了!可以说也是颇为感慨,个人认为,学 ...

  3. java学习笔记15--多线程编程基础2

    本文地址:http://www.cnblogs.com/archimedes/p/java-study-note15.html,转载请注明源地址. 线程的生命周期 1.线程的生命周期 线程从产生到消亡 ...

  4. 大数据学习笔记——Java篇之网络编程基础

    Java网络编程学习笔记 1. 网络编程基础知识 1.1 网络分层图 网络分层分为两种模型:OSI模型以及TCP/IP网络模型,前者模型分为7层,是一个理论的,参考的模型:后者为实际应用的模型,具体对 ...

  5. Java IO学习笔记四:Socket基础

    作者:Grey 原文地址:Java IO学习笔记四:Socket基础 准备两个Linux实例(安装好jdk1.8),我准备的两个实例的ip地址分别为: io1实例:192.168.205.138 io ...

  6. Linux 学习笔记之超详细基础linux命令 Part 10

    Linux学习笔记之超详细基础linux命令 by:授客 QQ:1033553122 ---------------------------------接Part 9----------------- ...

  7. TensorFlow学习笔记4-线性代数基础

    TensorFlow学习笔记4-线性代数基础 本笔记内容为"AI深度学习".内容主要参考<Deep Learning>中文版. \(X\)表示训练集的设计矩阵,其大小为 ...

  8. 【学习笔记】jQuery的基础学习

    [学习笔记]jQuery的基础学习 新建 模板 小书匠  什么是jQuery对象? jQuery 对象就是通过jQuery包装DOM对象后产生的对象.jQuery 对象是 jQuery 独有的. 如果 ...

  9. 【学习笔记】JavaScript的基础学习

    [学习笔记]JavaScript的基础学习 一 变量 1 变量命名规则 Camel 标记法 首字母是小写的,接下来的字母都以大写字符开头.例如: var myTestValue = 0, mySeco ...

随机推荐

  1. Python 学习笔记(6)--常用模块(2)

    一.下载安装 下载安装有两种方式: yum\pip\apt-get 或者源码 下载源码 解压源码 进入目录 编译源码 python setup.py build 安装源码 python setup.p ...

  2. 本人为巨杉数据库(开源NoSQL)写的C#驱动,支持Linq,全部开源,已提交github

    一.关于NoSQL的项目需求 这些年在做AgileEAS.NET SOA 中间件平台的推广.技术咨询服务过程之中,特别是针对我们最熟悉的医疗行业应用之中,针对大数据分析,大并发性能的需求,我们也在慢慢 ...

  3. iOS开发学习笔记

    1 常用的第三方工具 1.1 iPhone Simulator 测试程序需要模拟器iPhone Simulator 1.2 设计界面需要Interface Builder,Interface Buil ...

  4. Nginx+FastCGI运行原理

    Nginx不支持对外部程序的直接调用或者解析,所有的外部程序(包括PHP)必须通过FastCGI接口来调用.FastCGI接口在Linux下是socket(这个socket可以是文件socket,也可 ...

  5. Xcode 突然有部分文件不显示

    今天突然Xcode抽风了,突然我的项目中的文件好多不显示出来,本地文件夹都有,见鬼了..... 真心坑死了,于是乎就找度娘了,果然被我发现了 看见这个蓝色小时钟没呀,就是他在捣鬼,我点击一下变成灰色就 ...

  6. [leetcode] 提醒整理之进制

    12. Integer to Roman Given an integer, convert it to a roman numeral. Input is guaranteed to be with ...

  7. Android 图片圆角的简单方法

    package com.jereh.helloworld.activity.ui; import android.content.Context; import android.graphics.Ca ...

  8. 一些关于 checkbox的前台 jquery 操作 记录

    $(function() { //页面载入函数 var partList = jQuery.parseJSON( '${KeyWordsList}'); $.each(partList,functio ...

  9. c语言实现开灯问题

    开灯问题: 有n盏灯,编号为1~n,第1个人把所有灯打开,第2个人按下所有编号为2 的倍数的开关(这些灯将被关掉),第3 个人按下所有编号为3的倍数的开关(其中关掉的灯将被打开,开着的灯将被关闭),依 ...

  10. Gridview中几个Button的应用

    gridview中有三种方式添加button的应用,CommandField.ButtonField.TemplateField中加Button这三种方式.三种方式都可以实现同样的功能,但在实现某些功 ...