工作以来,代码越写越多,程序也越来越臃肿,效率越来越低,对于我这样一个追求完美的程序员来说,这是绝对不被允许的,于是除了不断优化程序结构外,内存优化和性能调优就成了我惯用的“伎俩”。

要对Java程序进行内存优化和性能调优,不了解虚拟机的内部原理(或者叫规范更严谨一点)是肯定不行的,这里推荐一本好书《深入Java虚拟机(第二版)》(Bill Venners著,曹晓刚 蒋靖 译,实际上本文正是作者阅读本书之后,对Java虚拟机的个人理解阐述)。当然了,了解Java虚拟机的好处并不仅限于上述两点好处。从更深一点的技术层面上看,了解Java虚拟机的规范和实现,将更加有助于我们编写高效、稳定的Java代码。比如,假如了解Java虚拟机的内存模型,了解虚拟机的内存回收机制,那么我们就不会过分依赖它,而会在需要的时候显式的”释放内存”(Java代码不能显式释放内存,但是可以通过释放对象引用告知垃圾回收器回收该对象需要被回收),以降低不必要的内存消耗;假如我们了解Java栈的工作原理,那么我们就可以通过减少递归层数,减少循环次数来降低堆栈溢出的风险。可能对于应用开发人员来说,可能不会直接去涉及这些Java虚拟机底层实现的工作,但是了解这些背景知识,或多或少,都会对我们写的程序产生潜移默化的好的影响。

本篇文章,将简明扼要的说明Java虚拟机的体系结构和内存模型,如有用词不妥或解释不准确之处,请不吝指正,深感荣幸!

Java 虚拟机体系结构

类装载子系统

Java虚拟机有两种类装载器,分别是启动类装载器和用户自定义装载器。

通类装载子系统通过类的全限定名(包名和类名,网络装载还包括 URL)将 Class 装载进运行时数据区。对于每一个被装载的类型,Java虚拟机都会创建一个java.lang.Class类的实例来代表该类型,该实例被放在内存中的堆区,而装载的类型信息则位于方法区,这一点和所有其他对象都是一样的。

类装载子系统在装载一个类型前,除了要定位和导入对应的二进制class文件外,还要验证导入类的正确性,为类变量分配并初始化内存,以及解析符号引用为直接引用,这些动作严格按照以下顺序进行:

1)装载——查找并装载类型的二进制数据;

2)连接——执行验证,准备以及解析(可选)

3)验证 确保被导入类型的正确性

4)准备 为类变量分配内存,并将其初始化为默认值

5)解析 把类型中的符号引用转换为直接应用

方法区

对于每一个被类装载子系统装载的类型,虚拟机都会保存下列数据到方法区:

  • 类型的全限定名
  • 类型超类的全限定名(java.lang.Object没有超类)
  • 类型是类类型还是接口类型
  • 类型的访问修饰符
  • 任何直接超接口的全限定名有序列表

除了上述基本类型信息,还将保存如下信息:

  • 类型的常量池
  • 字段信息(包括字段名、字段类型、字段修饰符)
  • 方法信息(包括方法名、返回类型、参数的数量和类型、方法修饰符,如果方法不是抽象和本地的,还将保存方法的字节码、操作数栈和该方法栈帧中的局部变量区的大小和异常表)
  • 常量以外的所有类变量(其实就是类的静态变量,因为静态变量是所有实例共享的,且与类型直接相关,所以他们是类一级的变量,作为类的成员被保存在方法区)

一个到类ClassLoader的引用

//返回的就是刚才保存的ClassLoader引用
String.class.getClassLoader();

一个到Class类的引用

//将返回刚才保存的Class类的引用
String.class;

注意,方法区也是可以被垃圾回收器回收的。

Java程序在运行时创建的所有类实例或数组都放在同一个堆中,而每一个Java虚拟机也是有一个对空间,所有线程共享一个堆(这就是一个多线程的Java程序会产生对象访问的同步问题的原因了)。

由于每一种Java虚拟机都有对虚拟机规范的不同实现,所以我们可能不知道每一种Java虚拟机在堆中是以何种形式表示对象实例的,不过我们可以通过下面这可能的实现来一窥端倪:

程序计数器

对于运行中的Java程序而言,每一个线程都有自己的PC(程序计数器)寄存器,它是在该线程启动时创建的,大小为一个字长,用来保存需要被执行的下一行代码的位置。

Java栈

每一个线程都有一个Java栈,以栈帧为单位保存线程的运行状态。虚拟机对Java栈的操作有两种:压栈和出栈,二者都已帧为单位。栈帧保存了传入参数、局部变量、中间运算结果等数据,在方法完成时被弹出,然后释放。

看一下两个局部变量相加时栈帧的内存快照

本地方法栈

这是 Java 调用操作系统本地库的地方,用来实现 JNI(Java Native Interface,Java 本地接口)

执行引擎

Java虚拟机的核心,控制装入 Java 字节码并解析;对于运行中的Java程序而言,每一个线程都是一个独立的虚拟机执行引擎的实例,从线程生命周期的开始到结束,他要么在执行字节码,要么在执行本地方法。

本地接口

连接了本地方法栈和操作系统库。

注:文中所有提到”Java虚拟机”的地方都是指”JavaEE和JavaSE平台的Java虚拟机规范”。

Java虚拟机体系结构深入研究总结的更多相关文章

  1. 理解Java虚拟机体系结构

    1 概述 众所周知,Java支持平台无关性.安全性和网络移动性.而Java平台由Java虚拟机和Java核心类所构成,它为纯Java程序提供了统一的编程接口,而不管下层操作系统是什么.正是得益于Jav ...

  2. Java虚拟机体系结构

    转自:http://www.cnblogs.com/java-my-life/archive/2012/08/01/2615221.html JAVA虚拟机的生命周期 一个运行时的Java虚拟机实例的 ...

  3. 理解Java虚拟机体系结构(转)

    1 概述 众所周知,Java支持平台无关性.安全性和网络移动性.而Java平台由Java虚拟机和Java核心类所构成,它为纯Java程序提供了统一的编程接口,而不管下层操作系统是什么.正是得益于Jav ...

  4. JAVA虚拟机体系结构JAVA虚拟机的生命周期

    一个运行时的Java虚拟机实例的天职是:负责运行一个java程序.当启动一个Java程序时,一个虚拟机实例也就诞生了.当该程序关闭退出,这个虚拟机实例也就随之消亡.如果同一台计算机上同时运行三个Jav ...

  5. 160323、理解Java虚拟机体系结构

    今天看到一篇文章,觉得写得不错,特拿来跟大家分享一下 1 概述 众所周知,Java支持平台无关性.安全性和网络移动性.而Java平台由Java虚拟机和Java核心类所构成,它为纯Java程序提供了统一 ...

  6. Java 虚拟机体系结构

    众所周知,Java源代码被编译器编译成class文件.而并不是底层操作系统可以直接执行的二进制指令(比如Windows OS的.exe文件).因此,我们需要有一种平台可以解释class文件并运行它.而 ...

  7. (转)Java 虚拟机体系结构

    来源:http://hxraid.iteye.com/blog/676235 众所周知,Java源代码被编译器编译成class文件.而并不是底层操作系统可以直接执行的二进制指令(比如Windows O ...

  8. JVM原理二----JAVA虚拟机体系结构

    组成: 指令集,寄存器,栈,无用单元收集(GC),方法区域.JAVA核心 1,指令集:这个不太清楚 2,寄存器:和处理器中的寄存器类似 pc:Java程序计数器. optop:指向*作数栈顶端的指针. ...

  9. 理解Android虚拟机体系结构

    1 什么是Dalvik虚拟机 Dalvik是Google公司自己设计用于Android平台的Java虚拟机,它是Android平台的重要组成部分,支持dex格式(Dalvik Executable)的 ...

随机推荐

  1. 马士兵 Servlet_JSP(3) Servlet和JSP的通信(源代码)

    (1)从JSP调用Servlet可用<jsp:forward>,请求信息自动转到Servlet FromJspToServlet.jsp <html>     <body ...

  2. poj 2226 Muddy Fields(最小点覆盖+巧妙构图)

      Description Rain has pummeled the cows' field, a rectangular grid of R rows and C columns (1 <= ...

  3. javaweb文件下载

    最近搞了一下struts文件上传下载了,一个是通过struts自带的类实现的下载方法,一个是通用的下载方法: struts实现: FileDownloadAction.java package com ...

  4. StoryBoard 加入一个自定义View

    1. 建一个 UIView的子类(MyView.h/MyView.m) 2. 建一个 View类型的XIB 3. 把xib的file‘s owner设为MyView 4. 在.h文件里加上 @prop ...

  5. jsf标签,jsp标签与jstl标签

    JSF通过定制标签与JSP集成.之前展示过的所有 JSF标签,<h:inputText>.<h:outputText>.<h:form> 和<f:view&g ...

  6. Thrift的安装和简单演示样例

    本文仅仅是简单的解说Thrift开源框架的安装和简单使用演示样例.对于具体的解说,后面在进行阐述. Thrift简述                                           ...

  7. Java之面向对象相关问题集

    面向对象的特征有哪些方面  1.抽象: 抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面.抽象并不打算了解所有问题,而仅仅是选择当中的一部分,临时不用部分细节. 抽 ...

  8. js中indexof()简单使用

    indexOf()方法返回某个指定的字符串值在字符串中首次出现的位置. stringObject.indexOf(searchvalue,fromindex):indexOf()方法对大小写敏感如果要 ...

  9. ASP.net button类控件click事件中传递参数

    单击Button会同时触发这两个事件,但先执行Click,后执行Command,在button控件中加上参数属性 CommandArgument='' 在click响应函数中可以用以下代码获得传递的参 ...

  10. mongodb 详解 error:10061 由于目标计算机积极拒绝,无法连接解决方法

    mongodb下载地址(32位):下载地址 自己选择版本 建立如下与mongodb并行的两个文件夹data和log. 然后建立mongo.config. 在mongo.config配置文件中输入: # ...