Java虚拟机学习记录(二)-运行时数据区域

一、前言

Java虚拟机在执行Java程序的过程中,会把他管理的内存划分为多个不同的数据区域,这些区域各自有各自的用途,以及创建和销毁的时间,有的区域随虚拟机进程的启动而存在,有的区域依赖用户线程的启动和结束而建立和销毁。

Java虚拟机所管理的内存将会包括以下几个运行时数据区域。
1.方法区(线程共享),JDK1.7中已经开始改变,JDK1.8中被元空间替代
2.堆(线程共享)
3.虚拟机栈(线程隔离)
4.本地方法栈(线程隔离)
5.程序计数器(线程隔离)

Java虚拟机运行时涉及到的另外的内存区域
1.直接内存

二、方法区(Method Area)

这是一个线程共享的数据区域,用来保存已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。Java虚拟机将方法区描述为堆的一个逻辑部分(在HotSpot中具体表现为在方法区的内存管理和堆中的内存管理是一套方案,当然这里的一套方案并不是说他们是一模一样的),但是方法区有一个别名叫做Non-Heap(非堆),应该是为了和堆作区别(Heap)。

在HotSpot虚拟机中,方法区又被很多人叫做“永久代”(Permanent Generation),本质上两者并不等价,仅仅是HotSpot团队将GC分代收集扩展至方法区,也就是使用永久代来实现方法区。这样就和Java堆使用了同样的GC分代收集策略,不必重新实现一套管理策略。对于其他虚拟机(如BEA JRockit、IBM J9等)来说是不存在永久代的。

然而在实际应用中,使用永久代来实现方法区并不是一个好的选择,更容易遇到内存溢出的问题。在JDK1.7中,已经将字符串常量池从永久代移出了。

字符串常量池的移出:JDK1.7 被转移到Java堆中(Java Heap)

Java虚拟机规范堆方法区的限制宽松,方法区不需要连续的内存,也可以不实现垃圾收集。事实上,垃圾收集的频率在这个区域是很小的,但是并不是所有在此的数据真的是“永久”的,这个区域的垃圾回收目标主要是针对常量池的回收和对类型的卸载。这个区域的回收成绩难以令人满意。当方法区无法满足内存分配的需求时,会抛出OutOfMemoryError的错误。

关于类型卸载,我理解为在Java虚拟机运行时,会将类信息加载到方法区,当某些类不会用到的时候(unreachable),就会从方法区中卸载这个类以节省内存),具体可以看下面的文章
1.Java类加载原理解析
2.Java虚拟机类型卸载和类型更新解析

在方法区中有一块叫做运行时常量池(Runtime Constant Pool)的区域,Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息常量池(Constant Pool Table),用于存放编译期生成的各种字面量和符号引用,这部分在类加载到方法区后进入运行时常量池。

字面量(literal): 我的理解为字面量指的几种基本类型。int,boolean,char,float,double,string,long,byte,null
其中float和double统称为floating-point literal,当你创建一个浮点数时,默认的是double类型。这也是为什么float a = 0.1;是错误的,你得float a = (float)0.1;
具体字面量的内容可以参考这里:Java Literals
符号引用: 符号引用是一个字符串,它给出了被引用的内容的名字并且可能会包含一些其他关于这个被引用项的信息——这些信息必须足以唯一的识别一个类、字段、方法。这样,对于其他类的符号引用必须给出类的全名。对于其他类的字段,必须给出类名、字段名以及字段描述符。对于其他类的方法的引用必须给出类名、方法名以及方法的描述符。
JVM中的直接引用和符号引用

关于常量池中的一些细节可以看这里的对比
Java常量池

方法区的变迁:
1、JDK1.2 ~ JDK6
在 JDK1.2 ~ JDK6 的实现中,HotSpot 使用永久代实现方法区;HotSpot 使用 GC 分代实现方法区带来了很大便利;

2、JDK7
由于 GC 分代技术的影响,使之许多优秀的内存调试工具无法在 Oracle HotSpot之上运行,必须单独处理;并且 Oracle 同时收购了 BEA 和 Sun 公司,同时拥有 JRockit 和 HotSpot,在将 JRockit 许多优秀特性移植到 HotSpot 时由于 GC 分代技术遇到了种种困难,所以从 JDK7 开始 Oracle HotSpot 开始移除永久代。
JDK7中符号表被移动到 Native Heap中,字符串常量和类引用被移动到 Java Heap中。

3、JDK8
在 JDK8 中,永久代已完全被元空间(Meatspace)所取代。
引用:Java 内存之方法区和运行时常量池

##三、堆(Java Heap)
和方法区一样,这也是一个线程共享的数据区域。在java虚拟机执行Java程序时,它占据了大多数的内存,几乎所有的对象的存储都是在这个区域。为什么说几乎呢?因为随着JIT编译器的发展和逃逸分析技术的逐渐成熟,栈上分配,标量替换优化技术将会导致一系列微妙的变化发生。

JIT编译器:及时编译器(Just-In-Time compiler)
逃逸分析技术:全部变量赋值,方法返回值,实例引用传递三种情况会发生指针逃逸,如果在方法内新建对象,并且这个对象没有离开过这个方法,则这个对象没有必要在堆中分配内存,直接在Java虚拟机栈中分配内存,省去了在堆中分配内存堆GC造成的压力。
什么是逃逸分析(Escape Analysis)?
栈上分配:将对象在栈上分配内存
标量替换优化技术:Java中的原始类型无法再分解,可以看作标量(scalar);指向对象的引用也是标量;而对象本身则是聚合量(aggregate),可以包含任意个数的标量。如果把一个Java对象拆散,将其成员变量恢复为分散的变量,这就叫做标量替换。拆散后的变量便可以被单独分析与优化,可以各自分别在活动记录(栈帧或寄存器)上分配空间;原本的对象就无需整体分配空间了。
HotSpot 17.0-b12的逃逸分析/标量替换的一个演示

Java堆是垃圾收集器管理的主要区域,又成”GC堆”(Garbage Collected Heap)。

从内存回收的角度来看,现在收集器基本都采用分代收集算法。所以Java堆可以细分为:新生代和老年代,再细分一点,可以分为Eden空间J,From Survivor空间,to Survivor空间

从内存分配的角度来看,Java堆可能划分出多个线程私有的分配缓冲区(Thread Local Allocation Buffer,TLAB)

Java堆的内存不要求在空间上是连续的,只要在逻辑上连续即可。

四、虚拟机栈(Java Virtual Machine Stack)

线程私有,和线程的生命周期相同。虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时,都会创建一个栈帧(Stack Frame),用于存储局部变量表,操作数栈,动态链接,方法出口等信息。每一个方法从调用到执行完成的过程,就对应着一个栈帧从虚拟机栈入栈到出栈的过程。

局部变量表中存放了编译区可知的各种基本数据类型(boolean,byte,char,int,float,double,long,short)、对象引用(reference,它不等同于对象本身,可能是一个指向对象起始地址的引用指针,也可能是指向一个代表对象的句柄和其他与此对象相关的位置)

64位的double和long会占据两个局部变量空间(slot),其余数据类型只占一个。局部变量表所需的空间在编译期间分配完成,当进入一个方法时,这个方法需要在帧中分配多少局部变量空间完全时确定的。

在Java虚拟机中,对这个区域规定了两中异常情况。1.如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError;如果虚拟机栈可以动态扩展,在扩展时无法申请到足够的内存,则会抛出OutOfMemoryError异常。

五、本地方法栈(Native Method Stack)

跟虚拟机栈类似,不过是用来存储本地方法的。

六、程序计数器(Program Counter Register)

线程私有,这是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器。字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支,循环,跳转,异常处理,线程恢复等基础功能都依赖这个。

每个线程都需要一个独立的程序计数器,保证各条线程执行中不会混乱。

如果当前执行的时Java方法,这个计数器记录的正是当前正在执行的虚拟机字节码指令的位置,如果执行的时Native方法,这个计数器为空。此区域时唯一一个在Java虚拟机规范中没规定任何OutOfMemoryError的区域。

七、直接内存(Direct Memory)

在JDK1.4中加入了NIO(New Input/Output)类,引入了一种基于通道(Channel)和缓冲区(Buffer)的I/O方式,它可以使用Native函数库直接分配堆外内存,然后通过一个存储在Java堆中的DirectByteBuffer对象作为这个内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了频繁的在Java堆中和Native堆中复制数据。

Java虚拟机学习记录(一)-Java技术体系

##一、java技术体系概览

JDK(Java Development Kit)

  • Java程序设计语言
  • Java虚拟机
  • Java API类库

JDK是用于支持Java程序开发的最小环境。

JRE(Java Runtime Environment)

  • Java SE API子集
  • Java虚拟机

JRE是支持Java程序运行的标准环境

Java语言 Java Language
工具及工具API Java Javac JavaDoc Jar Javap Monitor JPDA
JConsole Java VisualVM JavaDB security Internationalization JMC RMI
IDL Deploy JFR Troubleshoot Scripting JVMTI Web Services
程序部署和发布 Java Web Start Applet/Java Plug-in
用户界面工具集 JavaFX
Swing Java 2D AWT Accessbility
Drag and Drop Input Methods Image I/O Print Service Sound
集成库 IDL JDBC JNDI RMI RMI-IIOP Scripting
其他基础库 Beans Int’l Support Input/Output JMX
JNI NetWorking Override Mechanism
Security Serialization Extension Mechanism XML JAXP Mechanism
语言和工具基础库 Math Collections Concurrency Utilities JAR
Logging Management Preferences API Ref Objects
Reflection Regular Expressions Versioning Zip Instrumentation
Java虚拟机 Java HotSpot Client and Server VM

这张表网上有很多版本,我以《深入理解java虚拟机》为参考,添加了JMC和JFR。可能在这划分中会有重叠部分,仅做参考。
其中

  • JDK: Java语言,工具及工具API,程序部署发布,用户界面工具集,集成库,其他基础库,语言和工具基础库,Java虚拟机
  • JRE: 程序部署发布,用户界面工具集,集成库,其他基础库,语言和工具基础库,Java虚拟机
  • Java SE API: 用户界面工具集,集成库,其他基础库,语言和工具基础库,Java虚拟机

##二. Java工具和工具API(对应了jdk中bin目录下的工具)
###自己目前使用过的有:
– java : 用来运行jar。对应bin目录下的java。
– javac: java的编译工具。对应bin目录下的javac。
– JConsole : 配置好环境的情况下,可以在控制台输入jconsole打开,jconsole可以配合JMX(其他基础库),达到对运行中的java程序进行监控甚至动态修改变量值的作用。具体的使用可以参考这一篇JMX整理,对应bin目录下的jconsole。
– security :
– keytool: 这个工具可以生成key和certificate,具体使用可以参考这一篇Java Security:keytool工具使用说明,securitykeytool 。对应bin目录下的keytool工具。
– jarsigner: jar密匙签名工具
– kinit: 主要用于获取或缓存Kerberos协议的票据授权票据。
– klist: 允许用户查看本地凭据缓存和密钥表中的条目(用于Kerberos协议)。
– ktab: Kerberos密钥表管理工具,允许用户管理存储于本地密钥表中的主要名称和服务密钥。
– policytool: 策略工具,用于管理用户策略文件(.java.policy)。

###尚未使用过的有
– javaDoc : 使用 javdoc 编译 .java 源文件时,它会读出 .java 源文件中的文档注释,并按照一定的规则与 Java 源程序一起进行编译,生成文档。对应bin目录下的javadoc。
– jar : JAR(Java Archive,Java 归档文件),是java 开发工具中的一个工具,位于JDK的安装目录的bin目录下。它是一个打包工具,有点类似winrar压缩工具,虽然一般是用来打包.class文件,但是实际上其它文件也是可以打包的。对应bin目录下的jar。
– Javap : java反编译工具。对应bin目录下的javap。
– JPDA : Java Platform Debugger Architecture(JPDA:Java平台调试架构),Java虚拟机后端和调试平台前端组成
– 1.Java虚拟机提供了Java调试的功能
– 2.调试平台通过调试交互协议向Java虚拟机请求服务以对在虚拟机中运行的程序进行调试
– jdb: Java调试工具(Java Debugger),主要用于对Java应用进行断点调试。
– Java VisualVM : java性能分析工具,对应bin目录下的jvisualvm。
– JavaDB : java的数据库。
– Int’l:可能指的是internationalization,即国际化。这里很不确定,在bin目录下有一个native2ascii,本地编码到ASCII编码的转换器(Native-to-ASCII Converter),用于”任意受支持的字符编码”和与之对应的”ASCII编码和(或)Unicode转义”之间的相互转换。
– JFR: Java飞行记录(好奇怪的翻译,Java Flight Recordings)。Java Flight Recordings (JFR) — Java 飞行记录器 – part 1
– JMC: Java任务控制工具(java Mission Control)。对应bin目录下的jmc
– RMI: Java远程方法调用(Remote Method Invocation,之前用过类似与thrift这种跨语言的远程调用框架,原理是socket通信)。对应bin目录下的
– java-rmi: Java远程方法调用(Java Remote Method Invocation)工具,主要用于在客户机上调用远程服务器上的对象。
– rmic: Java RMI 编译器,为使用JRMP或IIOP协议的远程对象生成stub、skeleton、和tie类,也用于生成OMG IDL。
– rmid: Java RMI 激活系统守护进程,rmid启动激活系统守护进程,允许在虚拟机中注册或激活对象。
– rmiregistry: Java 远程对象注册表,用于在当前主机的指定端口上创建并启动一个远程对象注册表。
– jstatd: jstatd(VM jstatd Daemon)工具是一个RMI服务器应用,用于监测HotSpot JVM的创建和终止,并提供一个接口,允许远程监测工具附加到运行于本地主机的JVM上。
– serialver: 序列版本命令,用于生成并返回serialVersionUID。
– IDL: 与RMI类似,是面向对象的远程调用,但不同的是他是跨语言的。对应bin目录下的
– idlj: IDL转Java编译器(IDL-to-Java Compiler),用于为指定的IDL文件生成Java绑定。IDL意即接口定义语言(Interface Definition Language)。
– servertool: Java IDL 服务器工具,用于注册、取消注册、启动和终止持久化的服务器。
– tnameserv: Java IDL瞬时命名服务。
– orbd: 对象请求代理守护进程(Object Request Broker Daemon),它使客户端能够透明地定位和调用位于CORBA环境的服务器上的持久对象。
– deploy:
– javafxpackager: JavaFX包装器,用于执行与封装或签名JavaFX应用有关的任务。
– pack200: JAR文件打包压缩工具,它可以利用Java类特有的结构,对普通JAR文件进行高效压缩,以便于能够更快地进行网络传输。
– unpack200: JAR文件解压工具,将一个由pack200打包的文件解压提取为JAR文件。
– Monitor: 我这里理解为一系列的java运行监视工具
– JPS:JVM进程状态工具(JVM Process Status Tool),用于显示目标系统上的HotSpot JVM的Java进程信息。对应bin目录下的jps。
– JSTAT: JVM统计监测工具(JVM Statistics Monitoring Tool),主要用于监测并显示JVM的性能统计信息。对应bin目录下的jstat。
– Troubleshoot: java的一系列错误定位工具
– JINFO: Java配置信息工具(Java Configuration Information),用于打印指定Java进程、核心文件或远程调试服务器的配置信息。对应bin目录下的jinfo。
– JStack: Java堆栈跟踪工具,主要用于打印指定Java进程、核心文件或远程调试服务器的Java线程的堆栈跟踪信息。
– JMAP: ava内存映射工具(Java Memory Map),主要用于打印指定Java进程、核心文件或远程调试服务器的共享对象内存映射或堆内存细节。。对应bin目录下的jmap。
– jhat: Heap Dump Browser, 根据dump文件进行分析,可以在浏览器中查看。
– jsadebugd: Java可用性代理调试守护进程(Java Serviceability Agent Debug Daemon),主要用于附加到指定的Java进程、核心文件,或充当一个调试服务器。
– Scripting:
– jrunscript: Java命令行脚本外壳工具(command line script shell),主要用于解释执行javascript、groovy、ruby等脚本语言。
– JVMTI: Java 虚拟机工具接口(Java Virtual Machine Toolkit Interface),用于替代在先前的 JDK 版本中作为试验功能存在的 Java 虚拟机剖析接口(Java Virtual Machine Profiling Interface,JVMPI)和 Java 虚拟机调试接口(Java Virtual Machine Debugging Interface,JVMDI)。通过 JVMTI 接口可以创建代理程序(Agent)以监视和控制 Java 应用程序,包括剖析、调试、监控、分析线程等等。
– Web Services:
– wsgen: 当从 Java 代码启动时,wsgen 命令行工具将生成 Java API for XML Web Services (JAX-WS) 应用程序所必需的工件。
– wsimport: wsimport 命令行工具用于处理现有 Web Service 描述语言 (WSDL) 文件,并生成开发 Java API for XML-Based Web Services (JAX-WS) Web Service 应用程序所必需的工件。
– schemagen: XML schema生成器,用于生成XML schema文件。
– xjc: 主要用于根据XML schema文件生成对应的Java类。

##程序部署和发布
– Java Web Start:允许用户直接从网络上运行基于java技术的应用。共有三种运行方式,无论哪一种,都会连上网络运行
– 1.从网页上点击链接。
– 2.从桌面图标或者开始菜单。
– 3.从java缓存视图中。
– Applet/Java Plug-in)
applet小程序
##用户界面工具集
– JavaFx: 2007年首次推出,具体资料可以看这些。JavaFX对Java开发者到底意味着什么JavaFX: Getting Started with JavaFX
– Swing: 是所谓的Lightweight组件,不是通过native方法来实现的,所以Swing的窗口风格更多样化。但是,Swing里面也有heaveyweight组件。比如JWindow,Dialog,JFrame。Swing由纯Java写成,可移植性好,外观在不同平台上相同。所以Swing部件称为轻量级组件, Swing是由纯JAVA CODE所写的,因此SWING解决了JAVA因窗口类而无法跨平台的问题,使窗口功能也具有跨平台与延展性的特性,而且SWING不需占有太多系统资源,因此称为轻量级组件
– Java 2D:包括Graphics,Graphics2D接口。Trail: 2D Graphics
– AWT:调用系统的native接口绘制,所以风格和系统相关。由于不同 操作系统 的图形库所提供的功能是不一样的,在一个平台上存在的功能在另外一个平台上则可能不存在。为了实现Java语言所宣称的”一次编译,到处运行”的概念,AWT 不得不通过牺牲功能来实现其平台无关性,也就是说,AWT 所提供的图形功能是各种通用型操作系统所提供的图形功能的交集。由于AWT 是依靠本地方法来实现其功能的,我们通常把AWT控件称为重量级控件。
– Accessbility: 无障碍使用,针对残疾人士。Java Accessibility Guide
– Drag and Drop: 实现拖放功能。Lesson: Drag and Drop and Data Transfer
– Input Methods:用户输入
– Image I/O:图片的输入输出
– Print Service:打印服务
– Sound:声音

##三. 集成库
– IDL: Java IDL技术添加CORBA(Common Object Request Broker Architecture)到Java平台,提供了标准的互操性和连通性。Java IDL使得分布式,web的java应用能够使用OMG(Object Management Group)定义的行业标准的IDL(Interface Definition Language)语言和IIOP(Internet Inter-ORB Protocol) 协议透明的调用远程服务。
– JDBC: Java数据库连接API(Java Database Connectivity API)。
– JNDI: Java 命名与目录接口(Java Naming and Directory Interface),所有与系统外部的资源的引用,都可以通过JNDI定义和引用。通俗点理解我觉得应该就是将配置用xml保存。JNDI 是什么
– RMI: 远程方法调用API(Remote Method Invocation)。
– RMI-IIOP:通过IIOP(Internet Inter-ORB Protocol)协议的远程方法调用(RMI)。
– Scripting:能让java应用运行js引擎。

##四. 其他基础库
– Beans: Java Beans是Java中一种特殊的类,可以将多个对象封装到一个对象(bean)中。特点是
– 可序列化
– 提供无参构造器
– 提供getter方法和setter方法访问对象的属性。

名称中的“Bean”是用于Java的可重用软件组件的惯用叫法。

    public class PersonBean implements java.io.Serializable {

    /**
     * name 属性(注意大小写)
     */
    private String name = null;

    private boolean deceased = false;

    /** 无参构造器(没有参数) */
    public PersonBean() {
    }

    /**
     * name 属性的Getter方法
     */
    public String getName() {
        return name;
    }

    /**
     * name 属性的Setter方法
     * @param value
     */
    public void setName(final String value) {
        name = value;
    }

    /**
     * deceased 属性的Getter方法
     * 布尔型属性的Getter方法的不同形式(这里使用了is而非get)
     */
    public boolean isDeceased() {
        return deceased;
    }

    /**
     * deceased 属性的Setter方法
     * @param value
     */
    public void setDeceased(final boolean value) {
        deceased = value;
    }
}
  • Internationalization Support: 国际化支持。特点如下:
    • 额外的本土化数据和任何地方运行结果相同
    • 文字信息存储在代码之外,动态加载(方便程序的翻译)
    • 不需要重新编译就能支持新的语言
    • 基于文化的数据,比如日期,货币,呈现方式
    • 可以快速本土化
  • Input/Output: 输入/输出
    • 通过数据流、序列化、文件系统的输入输出
    • 字符集、解码、编码、byte到unicode直接的转换
    • 文件、文件属性、文件系统
    • 提供建立使用异步的或可复用的、无阻塞的输入输出的服务的API
    • java.io (description) – Supports system input and output, and object serialization. to the file system
    • java.nio (description) – Defines buffers for bulk memory operations. Buffers may be allocated in direct memory for high performance.
    • java.nio.channels (description) – Defines channels, an abstraction for devices capable of performing I/O operations; defines selectors for multiplexed, non-blocking I/O
    • java.nio.channels.spi (description) – Provides implementations for channels
    • java.nio.file – Defines interfaces and classes to access files and file systems.
    • java.nio.file.attribute – Defines interfaces and classes for accessing file system attributes.
    • java.nio.file.spi – Defines classes for creating a file system implementation.
    • java.nio.charset (description) – Defines charsets, decoders, and encoders, for translating between bytes and Unicode characters
    • java.nio.charset.spi (description) – Provides implementations for charsets
  • JMX: Java管理扩展(Java Management Extensions)。提供接口结合jconsole工具使用,可以实时查看java程序运行时的变量值,以及修改他们。
  • JNI: 提供java对c的支持,可以调用c的方法。
  • NetWorking: 提供使用URLS,URIS的类,socket类提供连接服务,安全功能。
  • Override Mechanism: 重载机制。
  • Security: 提供安全相关功能的API,例如可配置的访问控制,电子签名,认证和签名,加密,安全网络交互。
  • Serialization: 序列化,可以将对象(Object)序列化变成二进制流,然后从二进制流中读取出对象。
  • Extension Mechanism: 扩展机制。在我的理解中,是指java的包机制,类加载机制,包括从URL中获取。
    • java.lang.ClassLoader
    • java.lang.Package
    • java.lang.Thread
    • java.net.JarURLConnection
    • java.net.URLClassLoader
    • java.security.SecureClassLoader
  • XML JAXP Mechanism:提供丰富的API集用来处理XML文档和数据

##五. 语言和工具基础库
– Math: 提供和数学计算相关的方法
– Collections:
– 1.分为两类
– 最基本的一类是 java.util.Collection,有以下的后代
– java.util.Set
– java.util.SortedSet
– java.util.NavigableSet
– java.util.Queue
– java.util.concurrent.BlockingQueue
– java.util.concurrent.TransferQueue
– java.util.Deque
– java.util.concurrent.BlockingDeque
– 另外的一类是 java.util.Map,Map并不是真正的Collections,但是他们有着和Collections类似的接口,所以可以像Collections一样操作。
– java.util.SortedMap
– java.util.NavigableMap
– java.util.concurrent.ConcurrentMap
– java.util.concurrent.ConcurrentNavigableMap
– 2.许多Collections的修改操作都是可选的,当尝试使用没有实现的修改操作时会抛出UnsupportedOperationException,接口的实现必须明确哪些方法是支持的。
– 如果Collections不可修改,则是unmodifiable,如果可以修改,则是modifiable
– 如果Collections一成不变,则是immutable,如果是变化的,则是mutable
– 如果Lists的大小(Size)是不变的,则是fixed-size,否则则是variable-size.
– 如果Lists支持快速的索引访问(时间为常量),则是Random Access,不支持则是sequential access。RandomAccess标记接口意味着Lists支持Random Access。
– 3.有一些元素的存储是有限制的(比如Map的key–value)
– 是一个特定的类型
– 不能为null
– obey some arbitrary predicate
– 4.接口表格

    |Interface|HashTable|Resizable Array|Balanced Tree|Linked List|Hash Table + Linked List|
    |:----:|
    |Set      |HashSet  |               |TreeSet      |           |LinkedHashSet           |
    |List     |         | ArrayList     |             |LinkedList |                        |
    |Deque    |         | ArrayDeque    |             |LinkedList |                        |
    |Map      |HashMap  |               |TreeMap      |           |LinkedHashMap           |

- 5.AbstractCollection, AbstractSet, AbstractList, AbstractSequentialList and AbstractMap类已经提供了基本功能的实现
- 6.Concurrent Collection(提供多线程下的Collections)
    - 接口
        - BlockingQueue
        - TransferQueue
        - BlockingDeque
        - ConcurrentMap
        - ConcurrentNavigableMap
    类
        - LinkedBlockingQueue
        - ArrayBlockingQueue
        - PriorityBlockingQueue
        - DelayQueue
        - SynchronousQueue
        - LinkedBlockingDeque
        - LinkedTransferQueue
        - CopyOnWriteArrayList
        - CopyOnWriteArraySet
        - ConcurrentSkipListSet
        - ConcurrentHashMap
        - ConcurrentSkipListMap
- 7.额外注意事项
   -  HashTable在官方的Collections中并没有任何提及,通过查看HashTable的源代码,发现它是继承自Dictionary,实现了Map的接口。而HashMap则是Map的实现,继承的AbstractMap也是Map的实现
    - HashTable和HashMap有以下的区别:
        - HashMap => 不同步、可空键值、效率高、containsKey/containsValue
        - Hashtable => 同步、非空键值、效率略低、contains/containsKey/containsValue

8.这一部分的内容越整理越多,还是另开一篇去记录。

– Concurrency Utilities: 提供了一系列支持并发的接口和类
– java.util.concurrent
– java.util.concurrent.atomic:一系列的原子性类,比如AtomicInteger这样的,不需要额外的同步操作就可以支持并线程并发
– java.util.concurrent.locks:提供了多种锁机制

  • JAR: 提供格式化读写JAR文件的类
  • Logging: 提供日志功能
  • Management: 提供一系列标准的接口(JMX)用来管理资源,例如应用、设备、服务、Java虚拟机。关于JMX的内容上面以及整理过了。
  • Preferences API: 提供存储,读取用户和系统配置的方法。
  • Ref(Reference Objects): 提供了和垃圾收集器相关的接口,程序可以使用引用对象来获取一个对象的引用,这样做在之后的垃圾回收中仍然可能会将这个引用对象回收。程序也可以被设计成当垃圾收集器认为一个给定的对象的可达性(gc(垃圾回收)的可达性算法,这个在后续的垃圾回收算法中会整理出来)改变时被通知。因此,引用对象在设计简单的缓存时是很有用的,因为在低内存的情况下它会被自动回收,内存充裕时,因为对象保持了引用,所以不会被垃圾回收器回收。
  • Objects: 万物皆对象,你有吗。
  • Reflection: Java反射,也是很有用的一个库。spring的IOC就是Java反射的使用 。
  • Regular Expressions:正则表达式,也是很常用的库。
  • Versioning:可以让java程序在运行时被识别它的需求的运行环境的版本号。
  • Zip: 指的应该是Java Archive (JAR) Files,可以将多个文件压缩成一个的技术。
  • Instrumentation: 和Sound相关

##六. Java虚拟机
– HotSpot Client and Server VM: 现在我们最多接触到的应该就是HotSpot虚拟机了,但是在java最初发布到现在,出现过许多或经典或优秀或有特色的虚拟机实现。
– 1.Sun Classic/Exact VM
– 2.Sun HotSpot VM
– 3.Sun Mobile-Embedded VM/Meta-Circular VM
– 4.BEA JRockit/IBM J9 VM
– 5.Azul VM/BEA Liquid VM
– 6.Apache Harmony/Google Android Dalvik VM
– 7.Microsoft JVM及其他
##七.参考文章
1. JDK自带工具一览表
2. java监控工具(jps,jstat,jstack,jmap,jvisualvm等)
3. JDK Tools and Utilities
4. Java Web Start Technology
5. Java™ Platform Overview
6. Java™ Naming and Directory Interface (JNDI)
7. Java™ Internationalization Support
8. Java™ I/O, NIO, and NIO.2
9. The Extension Mechanism
10. Collections Framework Overview
11. Java Concurrency Utilities
12. 《深入理解Java虚拟机第一章》

c++和Java的对象内存异同

##前言

好久都没有写博客了。经过一段时间的实习,收获上感觉并不是很大,还好自己也有看一些东西。因为毕业设计做的是c++方面的编程,算是初探c++的内容。这里简单记录自己对c++和java的对象内存区别,谈谈c++为什么性能要比java高。想到哪里就记到哪里,因为很多东西自己也要查证才能确定。

##1.栈和堆

栈和堆在数据结构上是两种不同的结构,栈的特点是先进后出,而堆则可以看做是一大堆数据的集合。在c++和Java的内存中,也有堆和栈的概念。
首先理解一下,内存中栈中的每一个元素都被称为栈帧,每个栈帧中存储一个方法(function)中的用到的变量内存。程序执行时,就是一个栈中的每一帧被读取执行的过程。堆则是主要用来存储对象。那么在c++和java中到底有什么不同呢?

“`c++
object* processObject(int param){
object obj;
obj.param = param;
return &obj;
}

int main(){
object* obj = processObject(10);
obj->do_something(); //1
}

<pre><code><br />1处是会出现一个空指针错误的。而如果这是一段java的代码则完全没有问题。

在c++和java中,一个栈帧被执行完,这部分内存就直接被释放了。而在c++中,所有通过声明产生的对象都是在栈上开辟内存空间,所以函数执行完后这个对象也就被释放了,那么返回出来就是一个空指针了。只有通过new生成的对象才会在堆中申请空间,因此通过new出来的对象都需要在不用时手动释放内存,不然就会内存泄露。而在java中,对象是在堆中生成的(JDK7中的字符串是在常量池中,int等字面值在限定范围内也会在常量池中申请内存),所有方法内的对象都是一个指向堆中相应对象的指针(注意是指针而不是引用,很多人认为java中向方法传递参数是引用传递,但其实是值传递,只不过这个值是指向对象的指针)。而在java中不需要手动释放内存则是因为Java拥有GC机制(Garbage collect,垃圾回收)。这个在之后再谈。

##2 java的强弱引用和c++的智能指针

java的强弱引用和c++的智能指针都是在希望可以更好的进行内存管理的前提下出现的,java的强弱引用可以帮助GC机制进行粒度更细的内存回收,而c++的智能指针则是让没有GC机制的c++有了一定能力的自动释放内存的能力。
###a. java的强弱引用
java的引用共有四种,分别为强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference)。
之所以定义出这么多引用,是希望在GC发生时,可以更灵活的进行对象的销毁。

强引用就是通过new出来的对象,强引用表示的都是必需的对象,这是无论如何都不会被回收的。

而软引用则表示有用但非必需的对象。当系统内存不够将要发生内存溢出异常的时候,会将软引用的对象列入回收范围,进行二次回收。只有这次回收仍然内存不足才会抛出内存溢出异常。JDK1.2之后提供了SoftReference类来实现这个。

弱引用也用来表示非必需的对象,不同的是,这个引用并不能帮助对象躲过任何的GC,也就是说无论如何,发生GC时这个对象都会被回收,弱引用的唯一作用就是用来取得一个对象实例。JDK1.2之后提供了WeakReference类来实现这个。

综合上述,虚引用的存在也比较清晰了。它不仅不能帮助对象躲过GC,甚至不能取得对象的实例。唯一存在的用处就是当其引用的对象被GC回收时会收到一个系统的通知。JDK1.2之后使用PhantomReference类来实现。

###b. C++的智能指针
相比于Java的GC机制以及为GC服务的各种引用,C++的智能指针则稍显简单。但是这个看似简单的c++的智能指针,对于c++来说意义也许并不是那么低。在我的理解中,c++之所以实用,因为相对于c,c++有着丰富高效的STL库和被大多数开发者接受的OOP。对于一个巨大的项目来说,OOP往往可以更好的帮助系统模块化,降低耦合,而STL库则是开发者进行高效工作的基础。相对于Java,单单从c++没有GC机制,就意味着它有着更高的性能,另外Java的虚拟机也是影响性能的一个方面。可也是因为c++没有GC机制,对于一个多人合作的巨大的项目来说,内存泄露则是面临的首要问题。举个很低端的例子
“`c++
class Example{
Mysql* getMysqlConnect(){
Mysql* mysql = new Mysql;
return mysql;
}
};

一个项目中所有的mysql对象指针都通过上面的getMysqlConnect()获取,看似没有问题,但是没有人敢保证一个项目中所有使用这个方法的人都会在使用完mysql对象后,手动将其释放。因此这里需要一个shared_ptr或者unique_ptr去包装一下指针,这样调用函数的人就不需要在外部释放对象内存,也就避免了内存泄露的问题。当然在使用shared_ptr时也一定要注意,因为可能会出现循环引用的问题,循环引用则会导致对象内存一直不被释放。
当然了,上面的例子只是为了说明这个例子而列举出来的,事实上可以直接返回对象而不是指针。
c++
class Example{
Mysql getMysqlConnect(){
Mysql mysql;
return mysql;
}
};

这里我一开始以为是会将对象复制一遍返回出来,但事实上在c++11中有了移动语义,即这种在拷贝语义和移动语义中,会优先使用移动语义来将mysql对象从方法中移出来,而不是拷贝mysql对象返回,并把方法中的对象删除。
##3 c++如何尽量避免内存泄露

后天再写啦