搜档网
当前位置:搜档网 › jvm

jvm

jvm
jvm

JVM简介及工作原理分析

1、什么是JVM

JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。

简单来说,JVM是用于执行Java应用程序和字节码的软件模块,并且可以将字节码转换为特定硬件和特定操作系统的本地代码。JVM在执行字节码时,实际上最终还是把字节码解释成具体平台上的机器指令执行,这就是Java的能够“一次编译,到处运行”的原因。

JVM包括一套字节码指令集、一组寄存器、一个栈、一个垃圾回收堆和一个存储方法域。

2、JRE/JDK/JVM是什么关系

JRE(JavaRuntimeEnvironment,Java运行环境),也就是Java平台。所有的Java 程序都要在JRE下才能运行。普通用户只需要运行已开发好的java程序,安装JRE即可。

JDK(Java Development Kit)是程序开发者用来来编译、调试java程序用的开发工具包。JDK的工具也是Java程序,也需要JRE才能运行。为了保持JDK 的独立性和完整性,在JDK的安装过程中,JRE也是安装的一部分。所以,在JDK的安装目录下有一个名为jre的目录,用于存放JRE文件。

JVM(JavaVirtualMachine,Java虚拟机)是JRE的一部分。它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。JVM有自己完善的硬件架构,如处理器、堆栈、寄存器等,还具有相应的指令系统。Java语言最重要的特点就是跨平台运行。使用JVM就是为了支持与操作系统无关,实现跨平台。

3、JVM体系结构

JVM的内部体系结构分为三部分(图片来自网络):

(1)类装载器(ClassLoader)子系统

(2)执行引擎

(3)运行时数据区

4、JVM工作原理

JVM是java的核心和基础,在java编译器和os平台之间的虚拟处理器。它是一种基于下层的操作系统和硬件平台并利用软件方法来实现的抽象的计算机,可以在上面执行java的字节码程序。java编译器只需面向JVM,生成JVM能理解的代码或字节码文件。Java源文件经编译器,编译成字节码程序,通过JVM将每一条指令翻译成不同平台机器码,通过特定平台运行。可以用下图来表示编译执行的简化过程:

5、JVM执行过程

1、加载class文件;

2、分配内存;

3、解释字节码成机器码;

4、运行过程垃圾收集;

5、结束。

JRE(java运行时环境)由JVM构造的java程序的运行环,也是Java程序运行的环境,但是他同时一个操作系统的一个应用程序一个进程,因此他也有他自己的运行的生命周期,也有自己的代码和数据空间。

JVM在整个jdk中处于最底层,负责于操作系统的交互,用来屏蔽操作系统环境,提供一个完整的Java运行环境,因此也就虚拟计算机。操作系统装入JVM是通过jdk中Java.exe来完成,通过下面4步来完成JVM环境:

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

2) 装载JVM.dll

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

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

6、JVM的生命周期

a、两个概念

JVM实例和JVM执行引擎实例

JVM实例对应了一个独立运行的Java程序 (进程级别)

JVM执行引擎实例则对应了属于用户运行程序的线程 (线程级别)

b、JVM的生命周期

JVM实例的诞生

当启动一个Java程序时,一个JVM实例就产生了,任何一个拥有public static void main(String[] args)函数的class都可以作为JVM实例运行的起点

JVM实例的运行

main()作为该程序初始线程的起点,任何其他线程均由该线程启动。JVM内部有两种线程:守护线程和非守护线程,main()属于非守护线程,守护线程通常由JVM自己使用,java程序也可以标明自己创建的线程是守护线程。

JVM实例的消亡

当程序中的所有非守护线程都终止时,JVM才退出;若安全管理器允许,程序也可以使用Runtime类或者System.exit()来退出。

7、ClassLoader(类加载器)

a、JVM整个类加载过程

JVM将整个类加载过程划分为了三个步骤:

(1)装载

装载过程负责找到二进制字节码并加载至JVM中,JVM通过类名、类所在的包名通过ClassLoader来完成类的加载,同样,也采用以上三个元素来标识一个被加载了的类:类名+包名+ClassLoader实例ID。

(2)链接

链接过程负责对二进制字节码的格式进行校验、初始化装载类中的静态变量以及解析类中调用的接口、类。在完成了校验后,JVM初始化类中的静态变量,并将其值赋为默认值。最后一步为对类中的所有属性、方法进行验证,以确保其需要调用的属性、方法存在,以及具备应的权限(例如public、private域权限等),会造成NoSuchMethodError、NoSuchFieldError等错误信息。

(3)初始化

初始化过程即为执行类中的静态初始化代码、构造器代码以及静态属性的初始化,在四种情况下初始化过程会被触发执行:

1. 调用了new;

2. 反射调用了类中的方法;

3. 子类调用了初始化;

4. JVM启动过程中指定的初始化类。

b、JVM类加载顺序

JVM有两种类加载器:

启动类装载器:是JVM实现的一部分

用户自定义类装载器:是Java程序的一部分,必须是ClassLoader类的子类

当JVM启动时,由Bootstrap向User-Defined方向加载类;应用进行ClassLoader时,由User-Defined向Bootstrap方向查找并加载类;

1. Bootstrap ClassLoader

这是JVM的根ClassLoader,它是用C++实现的,JVM启动时初始化此ClassLoader,并由此ClassLoader完成$JAVA_HOME中jre/lib/rt.jar(Sun JDK的实现)中所有class文件的加载,这个jar中包含了java规范定义的所有接口以及实现。

2. Extension ClassLoader

JVM用此classloader来加载扩展功能的一些jar包。

3. System ClassLoader

JVM用此classloader来加载启动参数中指定的Classpath中的jar包以及目录,在Sun JDK中ClassLoader对应的类名为AppClassLoader。

4. User-Defined ClassLoader

User-DefinedClassLoader是Java开发人员继承ClassLoader抽象类自行实现的ClassLoader,基于自定义的ClassLoader可用于加载非Classpath中的jar以及目录。

有关ClassLoader抽象类的几个关键方法:

loadClass

此方法负责加载指定名字的类,ClassLoader的实现方法为先从已经加载的类中寻找,如没有则继续从parent ClassLoader中寻找,如仍然没找到,则从System ClassLoader中寻找,最后再调用findClass方法来寻找,如要改变类的加载顺序,则可覆盖此方法

findLoadedClass

此方法负责从当前ClassLoader实例对象的缓存中寻找已加载的类,调用的为native的方法。

findClass

此方法直接抛出ClassNotFoundException,因此需要通过覆盖loadClass或此方法来以自定义的方式加载相应的类。

findSystemClass

此方法负责从System ClassLoader中寻找类,如未找到,则继续从Bootstrap ClassLoader中寻找,如仍然为找到,则返回null。

defineClass

此方法负责将二进制的字节码转换为Class对象

resolveClass

此方法负责完成Class对象的链接,如已链接过,则会直接返回。

8、执行引擎

JVM通过执行引擎来完成字节码的执行,在执行过程中JVM采用的是自己的一套指令系统,每个线程在创建后,都会产生一个程序计数器(pc)和栈(Stack),其中程序计数器中存放了下一条将要执行的指令,Stack中存放Stack Frame,表示的为当前正在执行的方法,每个方法的执行都会产生Stack Frame,Stack Frame中存放了传递给方法的参数、方法内的局部变量以及操作数栈,操作数栈用于存放指令运算的中间结果,指令负责从操作数栈中弹出参与运算的操作数,指令执行完毕后再将计算结果压回到操作数栈,当方法执行完毕后则从Stack中弹出,继续其他方法的执行。

在执行方法时JVM提供了四种指令来执行:

(1)invokestatic:调用类的static方法

(2)invokevirtual:调用对象实例的方法

(3)invokeinterface:将属性定义为接口来进行调用

(4)invokespecial:JVM对于初始化对象(Java构造器的方法为:)以及调用对象实例中的私有方法时。

主要的执行技术有:解释,即时编译,自适应优化、芯片级直接执行

(1)解释属于第一代JVM,

(2)即时编译JIT属于第二代JVM,

(3)自适应优化(目前Sun的HotspotJVM采用这种技术)则吸取第一代JVM和第二代JVM的经验,采用两者结合的方式开始对所有的代码都采取解释执行的方式,并监视代码执行情况,然后对那些经常调用的方法启动一个后台线程,将其编译为本地代码,并进行优化。若方法不再频繁使用,则取消编译过的代码,仍对其进行解释执行。

9、JVM运行时数据区

PC寄存器(Program Counter Register)

(Program Counter Register)是一块较小的内存空间,它可以看做是当前线程所执行的字节码的行号指示器。在虚拟机的概念模型里(仅是概念模型,各种虚拟机可能会通过一些更高效的方式去实现),字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令、分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。

由于Java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的。在任何一个确定的时刻,一个处理器都只会执行一条线程中的指令。因此,为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各个线程之间计数器互不影响,独立存储。

如果线程正在执行的是一个Java方法,那这个计数器记录的是正在执行的字节码指令的地址;如果正在执行的是Native方法,这个计数器值则为空(undefined)。此内存区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。

程序计数器是线程私有的,它的生命周期与线程相同(随线程而生,随线程而灭)。

JVM栈(JVM Stacks)

每个JVM 线程都有一个私有的JVM 栈(Stacks),它将和线程同时创建。JVM 栈用来存储帧(后面会讲解)。JVM 栈类似于传统语言例如C 的栈,它持有局部变量和部分结果并且参与方法的调用和返回。由于JVM 栈除了压入弹出帧外不会被直接操作,所以帧可以由堆(Heap)来分配。对于JVM 栈的内存不必是连续的。

JVM 规范允许JVM 栈的大小是固定的,也可以是根据需求计算来扩展和收缩。如果JVM 栈是固定大小,则每个JVM 栈大小可以在栈创建时独立地选择。一个JVM 实现可以让程序员或用户控制JVM 初始栈的大小,以及在动态扩展或收缩JVM 栈时,控制其最大值和最小值。

以下异常情况常与JVM 栈有关:

如果线程中的计算需要一个比允许的JVM 栈更大时,JVM 将会抛出StackOverflowError.

如果JVM 栈可动态扩展,当没有足够的内存分配给所尝试的扩展,或者没有足够的内存来为一个新线程创建初始化JVM 栈,JVM 将会抛出OutOfMemoryError.

堆(Heap)

JVM 有一个所有JVM 线程间共享的堆(Heap)。堆是分配所有类实例和数组内存的运行期数据区域。堆在虚拟机启动时被创建。堆中对象的存储由自

动存储管理系统(常被称为垃圾回收器或GC)回收,对象从来不会被显示的回收。JVM 承担着非特殊类型的自动存储管理系统,当然存储管理技术也可以根据实现者的系统要求来选择。堆可以是固定大小或是根据需求计算进行扩展,或者也可以是当一个大的堆不必要时进行收缩。堆的内存不需要是连续的。

一个JVM 实现可以让开发者或者用户控制堆初始的大小,同样的,如果堆能够动态扩展或者收缩,可以控制其最大值和最小值。

以下异常情况常与堆有关:如果计算需求所须更多的堆无法由自动存储管理系统提供时,JVM 将会抛出OutOfMemoryError.

方法区域(Method Area)

(1)方法区域存放了所加载的类的信息(名称、修饰符等)、类中的静态变量、类中定义为final类型的常量、类中的Field信息、类中的方法信息,当开发人员在程序中通过Class对象中的getName、isInterface等方法来获取信息时,这些数据都来源于方法区域,可见方法区域的重要性,同样,方法区域也是全局共享的,在一定的条件下它也会被GC;当方法区域需要使用的内存超过其允许的大小时,会抛出OutOfMemory的错误信息。

(2)方法区在虚拟机启动时被创建。虽然方法区逻辑上是堆的一部分,但是简单的实现可以选择既不垃圾回收也不压缩它。该版本的JVM 规范不要求指定方法区的位置或者用于管理编译后代码的策略。方法区可以是固定大小,也可以根据需求计算扩展,并且当大的方法区不再需要时进行收缩。方法区的内存不需要是连续的。一个JVM 实现可以让开发者或用户控制方法区初始的大小,同样的,在可变大小方法区时,控制方法区的最大值和最小值。在Sun JDK中这块区域对应的为Permanet Generation,又称为持久代,默认为64M,可通过-XX:PermSize以及-XX:MaxPermSize来指定其大小。

运行时常量池(Runtime Constant Pool)

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

以下异常情况常与类或接口的常量池有关:当创建类或接口时,如果常量池的建立需要的内存不能被JVM 的方法区分配,JVM 会抛出OutOfMenoryError.

本地方法堆栈(Native Method Stacks)

本地方法栈(Native Method Stack)与虚拟机栈所发挥的作用是非常类似,它们之间的区别在于虚拟机栈为虚拟机执行Java方法服务,而本地方法栈则是为虚拟机使用到的Native方法服务。在虚拟机规范中对本地方法栈中方法使用的语言、使用方式与数据结构并没有强制规定,因此具体的虚拟机可以自由的实现它。

以下异常情况常与本地方法栈有关:

如果线程中计算所需的本地方法栈大于允许范围,JVM 会抛出StackOverflowError。

如果本地方法栈能动态扩展,当没有足够的内存分配给所尝试的扩展,或者没有足够的内存分配给新线程中创建的初始本地方法栈,JVM 就会抛出OutOfMemoryError。

与虚拟机栈一样,本地方法栈也是线程私有的。

JVM原理以及JVM内存管理机制

一、 JVM简介 JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。JVM工作原理和特点主要是指操作系统装入JVM是通过jdk中Java.exe来完成, 首先来说一下JVM工作原理中的jdk这个东西, .JVM 在整个jdk中处于最底层,负责于操作系统的交互,用来屏蔽操作系统环境,提供一个完整的Java运行环境,因此也就虚拟计算机. 操作系统装入JVM是通过jdk中Java.exe来完成。 通过下面4步来完成JVM环境. 1.创建JVM装载环境和配置 2.装载JVM.dll 3.初始化JVM.dll并挂界到JNIENV(JNI调用接口)实例 4.调用JNIEnv实例装载并处理class类。 对于JVM自身的物理结构,我们可以从下图了解:

JVM的一个重要的特征就是它的自动内存管理机制,在执行一段Java代码的时候,会把它所管理的内存划分 成几个不同的数据区域,其中包括: 1. 程序计数器,众所周知,JVM的多线程是通过线程轮流切换并 分配CPU执行时间的方式来实现的,那么每一个线程在切换 后都必须记住它所执行的字节码的行号,以便线程在得到CPU 时间时进行恢复,这个计数器用于记录正在执行的字节码指令的地址,这里要强调的是“字节码”,如果执行的是Native方法,那么这个计数器应该为null; 2.

3. Java计算栈,可以说整个Java程序的执行就是一个出栈入栈 的过程,JVM会为每一个线程创建一个计算栈,用于记录线程中方法的调用和变量的创建,由于在计算栈里分配的内存出栈后立即被抛弃,因此在计算栈里不存在垃圾回收,如果线程请求的栈深度大于JVM允许的深度,会抛出StackOverflowError 异常,在内存耗尽时会抛出OutOfMemoryError异常; 4. Native方法栈,JVM在调用操作系统本地方法的时候会使用到 这个栈; 5. Java堆,由于每个线程分配到的计算栈容量有限,对于可能会 占据大量内存的对象,则会被分配到Java堆中,在栈中包含了指向该对象内存的地址;对于一个Java程序来说,只有一个Java堆,也就是说,所有线程共享一个堆中的对象;由于Java堆不受线程的控制,如果在一个方法结束之后立即回收这个方法使用到的对象,并不能保证其他线程是否正在使用该对象;因此堆中对象的回收由JVM的垃圾收集器统一管理,和某一个线程无关;在HotSpot虚拟机中Java堆被划分为三代:o新生代,正常情况下新创建的对象会被分配到新生代,但如果对象占据的内存足够大以致超过了新生代的容量限 制,也可能被分配到老年代;新生代对象的一个特点是最 新、且生命周期不长,被回收的可能性高;

Java虚拟机(JVM)参数配置说明

Java虚拟机(JVM)参数配置说明 在Java、J2EE大型应用中,JVM非标准参数的配置直接关系到整个系统的性能。 JVM非标准参数指的是JVM底层的一些配置参数,这些参数在一般开发中默认即可,不需要任何配置。但是在生产环境中,为了提高性能,往往需要调整这些参数,以求系统达到最佳新能。另外这些参数的配置也是影响系统稳定性的一个重要因素,相信大多数Java开发人员都见过“O utOfMem ory”类型的错误。呵呵,这其中很可能就是JVM参数配置不当或者就没有配置没意识到配置引起的。 为了说明这些参数,还需要说说JDK中的命令行工具一些知识做铺垫。 首先看如何获取这些命令配置信息说明: 假设你是windows平台,你安装了J2SDK,那么现在你从cmd控制台窗口进入J2SDK安装目录下的bin目录,然后运行java命令,出现如下结果,这些就是包括java.exe工具的和J VM的所有命令都在里面。 ----------------------------------------------------------------------- D:\j2sdk15\bin>java Usage: java [-options] class [args...] (to execute a class) or java [-options] -jar jarfile [args...] (to execute a jar file) where options include: -client to select the "client" VM -server to select the "server" VM -hotspot is a synonym for the "client" VM [deprecated] The default VM is client.

Java之volatile的使用及其原理

一、volatile的作用 我们已经知道可见性、有序性及原子性问题,通常情况下我们可以通过Synchronized关键字来解决这些个问题,不过如果对Synchronized原理有了解的话,应该知道Synchronized是一个比较重量级的操作,对系统的性能有比较大的影响,所以,如果有其他解决方案,我们通常都避免使用Synchronized来解决问题。 而volatile关键字就是Java中提供的另一种解决可见性和有序性问题的方案。对于原子性,需要强调一点,也是大家容易误解的一点:对volatile变量的单次读/写操作可以保证原子性的,如long和double类型变量,但是并不能保证i++这种操作的原子性,因为本质上i++是读、写两次操作。 二、volatile的使用 关于volatile的使用,我们可以通过几个例子来说明其使用方式和场景。 1、防止重排序 我们从一个最经典的例子来分析重排序问题。大家应该都很熟悉单例模式的实现,而在并发环境下的单例实现方式,我们通常可以采用双重检查加锁(DCL)的方式来实现。其源码如下: package com.paddx.test.concurrent; public class Singleton { public static volatile Singleton singleton; /** * 构造函数私有,禁止外部实例化 */ private Singleton() {}; public static Singleton getInstance() { if (singleton == null) { synchronized (singleton) { if (singleton == null) { singleton = new Singleton(); } } } return singleton; } } 现在我们分析一下为什么要在变量singleton之间加上volatile关键字。要理解这个问题,先要了解对象的构造过程,实例化一个对象其实可以分为三个步骤: ?分配内存空间。 ?初始化对象。

Java虚拟机工作原理(JVM)

As the Java V irtual Machine is a stack-based machine, almost all of its instructions involve the operand stack in some way. Most instructions push values, pop values, or both as they perform their functions. Java虚拟机是基于栈的(stack-based machine)。几乎所有的java虚拟机的指令,都与操作数栈(operand stack)有关.绝大多数指令都会在执行自己功能的时候进行入栈、出栈操作。 1Java体系结构介绍 Javaís architecture arises out of four distinct but interrelated technologies, each of which is defined by a separate specification from Sun Microsystems: 1.1 Java体系结构包括哪几部分? Java体系结构包括4个独立但相关的技术 the Java programming language →程序设计语言 the Java class file format →字节码文件格式 the Java Application Programming Interface→应用编程接口 the Java V irtual Machine →虚拟机 1.2 什么是JVM java虚拟机和java API组成了java运行时。 1.3 JVM的主要任务。 Java虚拟机的主要任务是装载class文件并执行其中的字节码。 Java虚拟机包含了一个类装载器。 类装载器的体系结构 二种类装载器 启动类装载器 用户定义的类装载器 启动类装载器是JVM实现的一部分 当被装载的类引用另外一个类时,JVM就是使用装载第一个类的类装载器装载被引用的类。 1.4 为什么java容易被反编译? ●因为java程序是动态连接的。从一个类到另一个类的引用是符号化的。在静态连接的 可执行程序中。类之间的引用只是直接的指针或者偏移量。相反在java的class文件中,指向另一个类的引用通过字符串清楚的标明了所指向的这个类的名字。

JVM内存分配(栈堆)与JVM回收机制

Java 中的堆和栈 简单的说: Java把内存划分成两种:一种是栈内存,一种是堆内存。 在函数中定义的一些基本类型的变量和对象的引用变量都在函数的栈内存中分配。 当在一段代码块定义一个变量时,Java就在栈中为这个变量分配内存空间,当超过变量的作用域后,Java会自动释放掉为该变量所分配的内存空间,该内存空间可以立即被另作他用。 堆内存用来存放由new创建的对象和数组。 在堆中分配的内存,由Java虚拟机的自动垃圾回收器来管理。 在堆中产生了一个数组或对象后,还可以在栈中定义一个特殊的变量,让栈中这个变量的取值等于数组或对象在堆内存中的首地址,栈中的这个变量就成了数组或对象的引用变量。 引用变量就相当于是为数组或对象起的一个名称,以后就可以在程序中使用栈中的引用变量来访问堆中的数组或对象。 具体的说: 栈与堆都是Java用来在Ram中存放数据的地方。与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆。 Java的堆是一个运行时数据区,类的(对象从中分配空间。这些对象通过new、newarray、anewarray和multianewarray等指令建立,它们不需要程序代码来显式的释放。堆是由垃圾回收来负责的,堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,因为它是在运行时动态分配内存的,Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于要在运行时动态分配内存,存取速度较慢。 栈的优势是,存取速度比堆要快,仅次于寄存器,栈数据可以共享。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。栈中主要存放一些基本类型的变量(,int, short, long, byte, float, double, boolean, char)和对象句柄。 栈有一个很重要的特殊性,就是存在栈中的数据可以共享。假设我们同时定义: int a = 3; int b = 3; 编译器先处理int a = 3;首先它会在栈中创建一个变量为a的引用,然后查找栈中是否有3这个值,如果没找到,就将3存放进来,然后将a指向3。接着处理int b = 3;在创建完b的引用变量后,因为在栈中已经有3这个值,便将b直接指向3。这样,就出现了a与b同时均指向3的情况。这时,如果再令a=4;那么编译器会重新搜索栈中是否有4值,如果没有,则将4存放进来,并令a指向4;如果已经有了,则直接将a指向这个地址。因此a值的改变不会影响到b 的值。要注意这种数据的共享与两个对象的引用同时指向一个对象的这种共享是不同的,因为这种情况a的修改并不会影响到b, 它是由编译器完成的,它有利于节省空间。而一个对象引用变量修改了这个对象的内部状态,会影响到另一个对象引用变量。 String是一个特殊的包装类数据。可以用: String str = new String("abc"); String str = "abc"; 两种的形式来创建,第一种是用new()来新建对象的,它会在存放于堆中。每调用一次就会创建一个新的对象。 而第二种是先在栈中创建一个对String类的对象引用变量str,然后查找栈中有没有存放"abc",如果没有,则将"abc"存放进栈,并令str指向”abc”,如果已经有”abc”则直接令 str指向“abc”。 比较类里面的数值是否相等时,用equals()方法;当测试两个包装类的引用是否指向同一个对象时,用==,下面用例子说明上面的理论。 String str1 = "abc"; String str2 = "abc"; System.out.println(str1==str2); //true

Eclipse中JVM内存设置

Eclipse中JVM内存设置 eclipse.ini内存设置 -vmargs -Xms128M -Xmx512M -XX:PermSize=64M -XX:MaxPermSize=128M 这里有几个问题: 1. 各个参数的含义什么? 2. 为什么有的机器我将-Xmx和-XX:MaxPermSize都设置为512M之后Eclipse可以启动,而有些机器无法启动? 3. 为何将上面的参数写入到eclipse.ini文件Eclipse没有执行对应的设置? 下面我们一一进行回答 1. 各个参数的含义什么? 参数中-vmargs的意思是设置JVM参数,所以后面的其实都是JVM的参数了,我们首先了解一下JVM内存管理的机制,然后再解释每个参数代表的含义。 堆(Heap)和非堆(Non-heap)内存 按照官方的说法:“Java 虚拟机具有一个堆,堆是运行时数据区域,所有类实例和数组的内存均从此处分配。堆是在Java 虚拟机启动时创建的。”“在JVM中堆之外的内存称为非堆内存(Non-heap memo ry)”。可以看出JVM主要管理两种类型的内存:堆和非堆。简单来说堆就是Java代码可及的内存,是留给开发人员使用的;非堆就是JVM留给自己用的,所以方法区、JVM内部处理或优化所需的内存(如JIT编译后的代码缓存)、每个类结构(如运行时常数池、字段和方法数据)以及方法和构造方法的代码都在非堆内存中。 堆内存分配

JVM初始分配的内存由-Xms指定,默认是物理内存的1/64;JVM最大分配的内存由-Xmx指定,默认是物理内存的1/4。默认空余堆内存小于40%时,JVM就会增大堆直到-X mx的最大限制;空余堆内存大于70%时,JVM会减少堆直到-Xms的最小限制。因此服务器一般设置-Xms、-Xmx相等以避免在每次GC 后调整堆的大小。 非堆内存分配 JVM使用-XX:PermSize设置非堆内存初始值,默认是物理内存的1/64;由XX:MaxP ermSize设置最大非堆内存的大小,默认是物理内存的1/4。 JVM内存限制(最大值) 首先JVM内存限制于实际的最大物理内存(废话!呵呵),假设物理内存无限大的话,J VM内存的最大值跟操作系统有很大的关系。简单的说就32位处理器虽然可控内存空间有4GB,但是具体的操作系统会给一个限制,这个限制一般是2GB-3GB(一般来说Windows 系统下为1.5G-2G,Linux系统下为2G-3G),而64bit以上的处理器就不会有限制了。 2. 为什么有的机器我将-Xmx和-XX:MaxPermSize都设置为512M之后Eclipse可以启动,而有些机器无法启动? 通过上面对JVM内存管理的介绍我们已经了解到JVM内存包含两种:堆内存和非堆内存,另外JVM最大内存首先取决于实际的物理内存和操作系统。所以说设置VM参数导致程序无法启动主要有以下几种原因: 1) 参数中-Xms的值大于-Xmx,或者-XX:PermSize的值大于-XX:MaxPermSize; 2) -Xmx的值和-XX:MaxPermSize的总和超过了JVM内存的最大限制,比如当前操作系统最大内存限制,或者实际的物理内存等等。说到实际物理内存这里需要说明一点的是,如果你的内存是1024MB,但实际系统中用到的并不可能是1024MB,因为有一部分被硬件占用了。 3. 为何将上面的参数写入到eclipse.ini文件Eclipse没有执行对应的设置?

JVM内存大小配置方式

JVM内存大小配置方式 By:sheagle@https://www.sodocs.net/doc/6d4994491.html, 1.最简单的方式,tomcat当中进行配置 用记事本打开tomcat安装路径下bin文件夹中的Catalina.bat,在文件当中添加set JAV A_OPTS=-Xms256m-Xmx512m 该方式只适合于使用Catalina Start指令及其类似方式通过执行Startup.bat中的指令方式启动tomcat 2.在Eclipse当中配置tomcat的内存启动大小 Eclipse->Window->Preferences->Server->Runtime Environments->选中Apache Tomcat v5.0->点击Edit按钮->在弹出对话框里点击JRE后面的Installed JREs按钮->在弹出对话框中选中tomcat使用的那个JRE->点击Edit按钮->在弹出对话框中,找到Default VM Arguments,并在输入框中输入:-Xms256M-Xmx512M 该修改方式只适合于使用Eclipse启动tomcat 3.在注册表中修改tomcat大小 如果你的电脑上边安装了tomcat服务,那么你也可以通过以下设置来修改通过

服务启动时的tomcat内存。 打开tomcat安装路径下bin文件夹中的tomcat6w.exe。选中Java,修改Inital memory pool和Maximum memory pool 该修改方式只适合于使用“服务”方式启动tomcat 总结: 关于tomcat启动时JVM虚拟机内存大小的配置,针对每种情况会有多种不同的配置方式,基本上都是修改配 置文件中参数的大小,无论使用哪种配置方式进行配置,只要能达到效果即可

JVM工作原理

JVM工作原理 1.JVM是什么? 为java程序提供运行环境,将java字节码文件翻译成机器可执行的二进制程序。 2. JVM装入:操作系统通过jdk中的java.exe来装入JVM ①、创建JVM装载环境和配置 ②、装载JVM.dll ③、初始化JVM.dll并挂界到JNIENV(JNI调用接口)实例 ④、调用JNIEnv实例装载并处理class类 3. JVM装入环境,JVM提供的方式是操作系统的动态连接文件 基于Windows的实现的分析 ①、查找jre路径 Java是通过GetApplicationHome api来获得当前的Java.exe绝对路径 ②、查找JVM.dll F:\Java\jdk1.6.0_20\jre\bin\java.dll 或GetPublicJREHome HKEY_LOCAL_MACHINE\Software\JavaSoft\Java Runtime Environment ③、装载JVM.cfg文件 F:\Java\jdk1.6.0_20\jre\lib\i386\JVM.cfg jdk目录中jre\bin\server和jre\bin\client都有JVM.dll文件存在,而Java 正是通过JVM.cfg配置文件来管理这些不同版本的JVM.dll的 主要参数: -client KNOWN -server KNOWN -hotspot ALIASED_TO -client -classic WARN -native ERROR -green ERROR KNOWN表示JVM存在ALIASED_TO表示给别的JVM取一个别名 WARN表示不存在时找一个JVM替代ERROR表示不存在抛出异常 在运行Java XXX是,Java.exe会通过CheckJVMType来检查当前的JVM类型,Java可以通过两种参数的方式来指定具体的JVM类型,一种按照JVM.cfg文件中的JVM名称指定,第二种方法是直接指定: ①、Java –J ②、Java -XXaltJVM= 或Java -J-XXaltJVM= 如果是第一种参数传递方式,CheckJVMType函数会取参数…-J?后面的JVM名称,然后从已知的JVM配置参数中查找如果找到同名的则去掉该JVM名称前的…-?直接返回该值;而第二种方法,会直接返回“-XXaltJVM=”或“-J-XXaltJVM=”后面的JVM类型名称。如果在运行Java时未指定上面两种方法中的任一一种参数,CheckJVMType会取配置文件中

Java JVM参数设置及日志查看

基础知识-Java JVM参数设置及日志查看 JVM内存参数 -Xms:初始堆大小;默认值为物理内存的1/64(<1GB),默认(MinHeapFreeRatio 参数可以调整)空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制。-Xmx:最大堆大小;默认值为物理内存的1/4(<1GB) 默认(MaxHeapFreeRatio参数可以调整)空余堆内存大于70%时,JVM会减少堆直到-Xms的最小限制 -Xmn:年轻代大小(1.4or lator);注意:此处的大小是(eden+ 2 survivor space).与jmap -heap中显示的New gen是不同的。整个堆大小=年轻代大小+ 年老代大小+ 持久代大小。增大年轻代后,将会减小年老代大小.此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8 -XX:NewSize:设置年轻代大小(for 1.3/1.4) -XX:MaxNewSize:年轻代最大值(for 1.3/1.4) -XX:PermSize:设置持久代(perm gen)初始值物理内存的1/64 -XX:MaxPermSize:设置持久代最大值;默认值为物理内存的1/4。注意IBM的JDK设置此参数无效。 -Xss:每个线程的堆栈大小;JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K.更具应用的线程所需内存大小进行调整.在相同物理内存下,减小这个值能生成更多的线程.但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。一般小的应用,如果栈不是很深,应该是128k够用的大的应用建议使用256k。这个选项对性能影响比较大,需要严格的选择。 -XX:ThreadStackSize:Thread Stack Size;(0 means use default stack size) [Sparc: 512; Solaris x86: 320 (was 256 prior in 5.0 and earlier); Sparc 64 bit: 1024; Linux amd64: 1024 (was 0 in 5.0 and earlier); all others 0.],此值设置和-Xss设置相似,目前较多使用-Xss。 -XX:NewRatio:年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代)-XX:NewRatio=4表示年轻代与年老代所占比值为1:4,年轻代占整个堆栈的1/5 当Xms=Xmx并且设置了Xmn的情况下,该参数不需要进行设置。 -XX:SurvivorRatio:Eden区与Survivor区的大小比值;设置为8,则两个Survivor 区与一个Eden区的比值为2:8,一个Survivor区占整个年轻代的1/10 -XX:LargePageSizeInBytes:内存页的大小不可设置过大,会影响Perm的大小,默认为128m -XX:+UseFastAccessorMethods:原始类型的快速优化 -XX:+DisableExplicitGC:关闭System.gc();这个参数谨慎使用。 -XX:MaxTenuringThreshold:垃圾最大年龄;如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代. 对于年老代比较多的应用,可以提高效率.如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活时间,增加在年轻代即被回收的概率,该参数只有在串行GC时才有效。 -XX:+AggressiveOpts:加快编译 -XX:+UseBiasedLocking:锁机制的性能改善

JVM内存最大能调多大分析

JVM内存最大能调多大分析【经典】 2010-11-10 13:21 转载自 最终编辑 上次用weblogic 把 -XmxXXXX 设成2G,就启动不起来,设小点就起来了,当时很气,怎么2G都起不了,今天在看到了一篇解释,转过来了 这次一位老友提出了这个问题,记得当年一个java高手在blogjava提出后,被骂得半死。大家使用java -XmxXXXX -version版本得出了不同的结论。后来老友说大概是1800M左右,我当时反驳,“我设置过服务器8G内存,我使用两个tomcat,每个2G”。为此,我翻开所有的JVM的内存管理的c代码,没有任何结论。我不是linux内核程序员,但是我看过linux的源码,知道32位体系结构的计算机寻址空间是2^32=4G,intel Pentium Pro处理器寻址空间是36位,CPU内部增加了PAE寄存器。用于处理多出来的4根地址 线的使用,所以PAE的技术实现最大2^36=64G寻址。通过linux的内核源码,标准Linux内核对于物理内存的管理采用1:3的分配比例,即物理内存的1/4为内核空间(kernel space),剩下的3/4为用户进程空间(user space),因此,在一台4G内存的服务器上,用户进程可使用的内存最大也就是3G。当进程被内核调入CPU运行时,不同的地址空间数据会被调入4G以内的用户进程空间,其实就能用3G。 IA32架构上,单一进程是不能使用超过4G的内存空间的。但是我记得我给mysql server分配内存大约是左右,不是2的32次方-1,我分配java 2G内存的计算机是IBM的RS6000. 经过不同平台的测试,我得出了大概的数值,win2k下左右,nt下,原因是这样的,Classic VM and HotSpot VM 存放用户区的连续地址中,NT把 kernel DLLs 放在 0x7c 开头的地址空间,所以nt下只有<2G的空间,所以JVM heap 使用极限是2G.用户的dll开始于0x,用户的应用程序开始于0x00400000.我现在唯一确定的是sun可能为了防止和某些 JVM插件的冲突,把dll的地址给rebase一下,这样使用的空间就很少了一部分.为什末rebase,原因是这样的,因为在windows下编译 dll 的默认地址都是, 一般在release之前的时候要rebase一下,rebase 的-b 这个参数是指定一个起始地址,MSDN建议地址是0x,这个工具随visual studio和platform SDK发放。 例如 -b 0x6D000000 \jdk\jre\bin\*.dll \jdk\jre\bin\hotspot\这样你的JVM用的内存多一些,目前关于这个我只能得到BEA的 JRockit最大也只能使用内存,看来各家编译JDK时都作了些手脚. 目前只能得到bea的的-Xmx最小值是16 MB,sun的资料很不全,还好java开源了,可以不依靠sun了. sun提供的资料 Maximum Address Space Per Process Operating System Maximum Address Space Per Process

JVM调优

首先需要注意的是在对JVM内存调优的时候不能只看操作系统级别Java进程所占用的内存,这个数值不能准确的反应堆内存的真实占用情况,因为GC过后这个值是不会变化的,因此内存调优的时候要更多地使用JDK提供的内存查看工具,比如JConsole和Java VisualVM。 对JVM内存的系统级的调优主要的目的是减少GC的频率和Full GC的次数,过多的GC和Full GC是会占用很多的系统资源(主要是CPU),影响系统的吞吐量。特别要关注Full GC,因为它会对整个堆进行整理,导致Full GC一般由于以下几种情况: 旧生代空间不足 调优时尽量让对象在新生代GC时被回收、让对象在新生代多存活一段时间和不要创建过大的对象及数组避免直接在旧生代创建对象 Pemanet Generation空间不足 增大Perm Gen空间,避免太多静态对象 统计得到的GC后晋升到旧生代的平均大小大于旧生代剩余空间 控制好新生代和旧生代的比例 System.gc()被显示调用 垃圾回收不要手动触发,尽量依靠JVM自身的机制 调优手段主要是通过控制堆内存的各个部分的比例和GC策略来实现,下面来看看各部分比例不良设置会导致什么后果 1)新生代设置过小 一是新生代GC次数非常频繁,增大系统消耗;二是导致大对象直接进入旧生代,占据了旧生代剩余空间,诱发Full GC

2)新生代设置过大 一是新生代设置过大会导致旧生代过小(堆总量一定),从而诱发Full GC;二是新生代GC耗时大幅度增加 一般说来新生代占整个堆1/3比较合适 3)Survivor设置过小 导致对象从eden直接到达旧生代,降低了在新生代的存活时间 4)Survivor设置过大 导致eden过小,增加了GC频率 另外,通过-XX:MaxTenuringThreshold=n来控制新生代存活时间,尽量让对象在新生代被回收 由内存管理和垃圾回收可知新生代和旧生代都有多种GC策略和组合搭配,选择这些策略对于我们这些开发人员是个难题,JVM提供两种较为简单的GC策略的设置方式 1)吞吐量优先 JVM以吞吐量为指标,自行选择相应的GC策略及控制新生代与旧生代的大小比例,来达到吞吐量指标。这个值可由-XX:GCTimeRatio=n来设置 2)暂停时间优先 JVM以暂停时间为指标,自行选择相应的GC策略及控制新生代与旧生代的大小比例,尽量保证每次GC造成的应用停止时间都在指定的数值范围内完成。这个值可由-XX:MaxGCPauseRatio=n来设置

synchronized和LOCK的实现原理---深入JVM锁机制--比较好

JVM底层又是如何实现synchronized的? 目前在Java中存在两种锁机制:synchronized和Lock,Lock接口及其实现类是JDK5增加的内容,其作者是大名鼎鼎的并发专家Doug Lea。本文并不比较synchronized与Lock 孰优孰劣,只是介绍二者的实现原理。 数据同步需要依赖锁,那锁的同步又依赖谁?synchronized给出的答案是在软件层面依赖JVM,而Lock给出的方案是在硬件层面依赖特殊的CPU指令,大家可能会进一步追问:JVM底层又是如何实现synchronized的? 本文所指说的JVM是指Hotspot的6u23版本,下面首先介绍synchronized的实现: synrhronized关键字简洁、清晰、语义明确,因此即使有了Lock接口,使用的还是非常广泛。其应用层的语义是可以把任何一个非null对象作为"锁",当synchronized作用在方法上时,锁住的便是对象实例(this);当作用在静态方法时锁住的便是对象对应的Class实例,因为Class数据存在于永久带,因此静态方法锁相当于该类的一个全局锁;当synchronized作用于某一个对象实例时,锁住的便是对应的代码块。在HotSpot JVM实现中,锁有个专门的名字:对象监视器。 1. 线程状态及状态转换 当多个线程同时请求某个对象监视器时,对象监视器会设置几种状态用来区分请求的线程: Contention List:所有请求锁的线程将被首先放置到该竞争队列 Entry List:Contention List中那些有资格成为候选人的线程被移到Entry List Wait Set:那些调用wait方法被阻塞的线程被放置到Wait Set OnDeck:任何时刻最多只能有一个线程正在竞争锁,该线程称为OnDeck Owner:获得锁的线程称为Owner !Owner:释放锁的线程 下图反映了个状态转换关系:

JVM内存设置方法

几招轻松搞定JVM内存设置 2010-09-17 14:04 gk23 javaeye 我要评论(0)字号:T | T 你知道如何进行JVM内存设置吗,这里向大家描述一下,设置JVM内存的参数有四个:分别是-Xss 每个线程的Stack大小;-Xmx Java Heap最大值;-Xms Java Heap初始值和-Xmn Java Heap Young区大小。 AD:本文向大家简单介绍一下进行JVM内存设置几种方法,安装Java开发软件时,默认安装包含两个文件夹,一个JDK(Java开发工具箱),一个JRE(Java运行环境,内含JVM),其中JDK内另含一个JRE。如果只是运行Java程序,则JRE已足够;而JDK则只有开发人员才用到。这里将为大家介绍设置JVM内存分配的几招。 浅谈JVM内存设置的几个妙招 一、设置JVM内存设置 1. 设置JVM内存的参数有四个: -Xmx Java Heap最大值,默认值为物理内存的1/4,最佳设值应该视物理内存大小及计算机内其他内存开销而定; -Xms Java Heap初始值,Server端JVM最好将-Xms和-Xmx设为相同值,开发测试机JVM可以保留默认值; -Xmn Java Heap Young区大小,不熟悉最好保留默认值; -Xss 每个线程的Stack大小,不熟悉最好保留默认值; 2. 如何分配JVM内存设置: (1)当在命令提示符下启动并使用JVM时(只对当前运行的类Test生效): 1.java -Xmx128m -Xms64m -Xmn32m -Xss16m Test 2. (2)当在集成开发环境下(如eclipse)启动并使用JVM时: a. 在eclipse根目录下打开eclipse.ini,默认内容为(这里设置的是运行当前开发工具的JVM内存分配):

JVM的内存机制介绍

本文分为两个部分: 1,JVM specification s(JVM规范) 对JVM内存的描述 2,Sun的JVM的内存机制。 JVM specification对JVM内存的描述 首先我们来了解JVM specification中的JVM整体架构。如下图: 主要包括两个子系统和两个组件: Class loader(类装载器) 子系统,Execution engine(执行引擎) 子系统;Runtime data area (运行时数据区域)组件, Native interface(本地接口)组件。 Class loader子系统的作用:根据给定的全限定名类名(如 https://www.sodocs.net/doc/6d4994491.html,ng.Object)来装载class文件的内容到 Runtime data area中的method area(方法区域)。Javsa程序员可以extends https://www.sodocs.net/doc/6d4994491.html,ng.ClassLoader类来写自己的Class loader。 Execution engine子系统的作用:执行classes中的指令。任何JVM specification实现(JDK)的核心是Execution engine,换句话说:Sun 的JDK 和IBM的JDK好坏主要取决于他们各自实现的Execution engine的好坏。每个运行中的线程都有一个Execution engine的实例。 Native interface组件:与native libraries交互,是其它编程语言交互的接口。 Runtime data area 组件:这个组件就是JVM中的内存。下面对这个部分进行详细介绍。

Runtime data area的整体架构图 Runtime data area 主要包括五个部分:Heap (堆), Method Area(方法区域), Java Stack(java的栈), Program Counter(程序计数器), Native method stack(本地方法栈)。Heap 和Method Area是被所有线程的共享使用的;而Java stack, Program counter 和Native method stack是以线程为粒度的,每个线

java序列化原理与算法

Java序列化原理和算法 总结: java中序列化算法的顺序: 1、子类的类信息描述 2、子类的字段信息描述(如果遇到类对象的属性,暂时用string的指针表示) 3、父类的类信息描述 4、父类的字段信息描述 5、对父类的字段信息进行赋值 6、对子类的字段信息进行赋值 7、发现子类的字段为类对象时,描述该类对象,并查找该类对象的父类,以以上方式描述,然后赋值。 本文讲解了Java序列化的机制和原理。从文中你可以了解如何序列化一个对象,什么时候需要序列化以及Java序列化的算法。 有关Java对象的序列化和反序列化也算是Java基础的一部分,下面对Java序列化的机制和原理进行一些介绍。 Java序列化算法透析 Serialization(序列化)是一种将对象以一连串的字节描述的过程;反序列化deserialization 是一种将这些字节重建成一个对象的过程。Java序列化API提供一种处理对象序列化的标准机制。在这里你能学到如何序列化一个对象,什么时候需要序列化以及Java序列化的算法,我们用一个实例来示范序列化以后的字节是如何描述一个对象的信息的。 序列化的必要性 Java中,一切都是对象,在分布式环境中经常需要将Object从这一端网络或设备传递到另一端。 这就需要有一种可以在两端传输数据的协议。Java序列化机制就是为了解决这个问题而产生。如何序列化一个对象 一个对象能够序列化的前提是实现Serializable接口,Serializable接口没有方法,更像是个标记。 有了这个标记的Class就能被序列化机制处理。 import java.io.Serializable; class TestSerial implements Serializable { public byte version = 100; public byte count = 0; } 然后我们写个程序将对象序列化并输出。ObjectOutputStream能把Object输出成Byte流。 我们将Byte流暂时存储到temp.out文件里。 public static void main(String args[]) throws IOException { FileOutputStream fos = new FileOutputStream("temp.out");

Java 精髓

从宏观上看,编程技术的发展在一定程度上映射了历史的发展。正如人类社会起源于极其简单的原始社会,早期的编程技术具有同样的规律;正如伟大的文明要经历萌芽、繁荣和衰落的过程,编程语言也同样会经历这些过程。国家的兴亡交替促进了人类的进步。同样,编程技术也处于不断的新旧更替之中:新的编程语言取代原来的编程语言。纵观人类历史,总不乏一些关键性事件,例如罗马帝国的颠覆、1066年的不列颠入侵,还有第一次核爆炸,它们都彻底改变了原来的世界。对于编程语言来说,虽然变革的规模较小,但同样改变了编程技术的发展进程。例如,FORTRAN语言的发明彻底改变了计算机编程的方式。Java的发明,则是另一个重大事件。 Java是标志编程进入Internet时代的里程碑。Java的设计初衷就是用来创建可以在Internet 上随处运行的应用程序,其“一次编写,随处运行”的理念定义了一种新的编程规范。Gosling 等人最初将其视为小型问题的解决方案,但后来却成为下一代程序员规划编程前景的动力。Java从根本上改变了人们对于编程的认识,因此计算机语言的发展历史可划分为两个时代:Java前时代和Java后时代。 Java前时代的程序员编写在单机上运行的程序;而Java后时代的程序员则为分布式网络环境编写程序。程序员不再只考虑单机的需求;相反,如今“网络就是计算机”的理念非常流行,程序员应该以服务器、客户端和主机的概念进行思考。 虽然Java的发展是由Internet所驱动的,但Java决不只是一种“Internet语言”。相反,它是一种特征(featuree)完备、为现代网络世界设计的通用编程语言。这意味着Java适合于几乎所有类型的编程。尽管有时候Java受限于网络性能,但它仍然包容了许多推进编程技术发展的新特征。这些特征不断影响着如今的计算模式。例如,Java提出的许多原理后来被C#所模仿。 本书将通过各种类型的应用程序来全面阐述Java语言的功能。其中一些应用程序展示了Java语言独立于网络属性(attribute)的强大功能,即所谓“纯代码”的范例,因为它们展示了Java语法的表示方法和设计思想。一些应用程序展示了如何使用Java语言及其API类简化复杂的网络编程。所有这些应用程序都说明了Java语言的强大功能和广泛应用范围。 在开始本书的Java教程之前,本章会用一些篇幅指出Java的一些特征,它们是Java作为一种优秀编程语言的标志。同时,这些特征也是将本章命名为“Java精髓”的原因所在。 1.1 简单数据类型和对象:完美的平衡 设计一种面向对象语言所面临的最大挑战,就是如何平衡对象和简单数据类型之间的抉择。从纯理论的观点来看,每种数据类型都应该是一个对象,并且都应该从一个共同的父对象派生而来。这就使得所有数据类型以相同的基本模式运作,共享一个公共的基类属性集合。现在的问题在于,如果将简单数据类型(如int和double)作为对象处理,那么对象机制所引起的额外开销会导致性能(performace)的下降。由于简单数据类型通常用于循环控制和条件语句,所以这些额外开销将带来广泛的负面影响。诀窍就是如何在“一切都是对象”的理想和“性能衡量”的现实之间找到正确的平衡点。 Java非常巧妙地解决了对象与简单数据类型之间的问题。首先,Java定义了8种简单类型:byte、short、int、long、char、float、double和boolean。这些类型能够直接转换为二进制代码。因此,CPU可以直接处理int类型的变量,而无需任何额外开销。在Java中,处理简单数据类型和其他语言一样快速高效。因此,由int类型变量所控制的for循环可以高速运行,而不受任何对象化所带来的负面影响。 除了这些简单数据类型,Java中的其他数据类型都从一个共同超类(Object类)派生而来。因此,所有这些数据类型都共享从父类继承而来的方法和属性集。例如,所有对象都有toString()方法,因为toString()是父类Object中定义的方法。 由于简单数据类型不是对象,因此Java可自由地以略有不同的方式处理对象和非对象。这

Java新手必学的21个技术点

Java新手必学的21个技术点 以下为大家盘点作为Java新手必学的21个技术点,希望能够对想要学习编程,学习JAVA的人有些帮助! JNI Java Native Interface,可以允许Java中调用本地接口方法,一般用于C/C++代码的调用。需要注意的是在java中加载so/dll文件的路径问题,本身调用接口并不复杂,但是经常在是否加载了所需的本地接口库中花费较多时间 RMI RemoteMethodInvocation ,java语言特有的远程调用接口,使用还是比较简单方便。不过需要跨语言的情况下,就需要使用 webservice 等其他方式来支持。一般来说,程序都不需要使用RMI,不过可以在特定的情况下使用,我就在一个项目中,使用RMI来进行程序远程启动停止的控制。 标注 也是jdk5 之后引入的。Spring是个优秀的框架,最开始就以xml作为标准的配置文件。不过到了Spring3 之后,尤其是 spring-boot 兴起之后,越来越推崇使用标注来简化xml配置文件了,对于开发者来说,可以节省不少xml配置的时间。但是劣势是在于标注散落在各个类中,不像xml,可以对所有配置有个全局性的理解和管理,所以还没有办法说完全就取代所有的xml。对于一般开发者,会使用标注即可,一些公共组建的开发者可能会需要了解标注的定义和实现,可以在具体需要的时候再细看。 泛型

这是JDK5开始引入的新概念,其实是个语法糖,在编写java代码时会有些许便利,一般的应用或者是业务的开发,只需要简单使用,不一定会用到定义泛型这样的操作,但是开发一些基础公共组件会使用到,可以在需要的时候再细看这个部分,一般情况下只要会简单使用即可。 Maven的使用 Maven 也不是Java里面的内容,但是maven是革命性的,给java开发带来了巨大的便利。从依赖的引入和管理,开发流程的更新和发布产出,乃至版本的更新,使用maven可以大大简化开发过程中的复杂度,从而节省大量时间。可以说,maven已经成为java开发者的标配了。所以我把maven也作为一个java开发者对于基础必备的知识点。以后会再放上一些我的一些对于maven使用的经验和技巧等,这里就不再细说了 XML解析/ JSON解析 其实这两块内容都不是J2SE里面的内容,但是在日常开发中,和其他程序交互,和配置文件交互,越来越离不开这两种格式的解析。 不过对于一个开发者来说,能够了解一些XML/JSON具体解析的原理和方法,有助于你在各个具体的场景中更好的选择合适你的方式来使得你的程序更有效率和更加健壮。 XML:需要了解 DOM解析和 SAX解析的基本原理和各自的适用场景JSON:需要了解一些常用JSON框架的用法, 如 Jackson, FastJson, Gson 等。 时间日期处理

相关主题