搜档网
当前位置:搜档网 › JVM内存分配过程与原理详解(雷惊风)

JVM内存分配过程与原理详解(雷惊风)

JVM内存分配过程与原理详解(雷惊风)
JVM内存分配过程与原理详解(雷惊风)

JVM内存分配过程与原理解析

之前对java虚拟机对于内存的分配与管理不是很了解,这段时间工作不是很忙,想借此机会深入的了解一下,在网上看了很多文章,对其详情也有了一定的认识,但是只是看看肯定是不行的,为了加深印象同时使自己能够理解的更深刻,我决定写这篇文章,同时希望对大家也有一定的帮助。文章里引用了其他前辈的一些资源,在这里表示感谢,那么我们就先从内存区域说起吧!

一.内存分区。

首先Java程序运行Java代码是发生在JVM上的,JMV相当于是java程序与操作系统的桥梁,JVM具有平台无关特性,所以java程序便可以在不同的操作系统上运行。Java的内存分配就是发生在JVM上的。对于java的内存回收我们并不用像其他有些语言一样手动回收,虚拟机就帮我们解决了,也正因为如此,如果我们写代码的时候不注意,很容易出现内存泄漏或者内存溢出(OOM),一旦出现问题,排查也不是很容易,所以只有了解了java的内存机制,才能更好的处理代码,优化代码。下边我们看一下java内存的几个部分,如下图:

由上图可知java内存共由java堆区(Heap)、java栈区(Stack)、方法区(Method Area)、本地方法栈(Native Method Stack)、程序计数器五部分组成,下面我们一一简单的讲解一下每一个区间的不同作用。

1.java堆区

首先要讲的就是我们的java堆,也就是人们常说的堆栈堆栈里边的堆,通过上图可知堆区是JVM中所有线程共享的内存区域,当运行一个应用程序的时候就会初始化一个相应的堆区,堆区可以动态扩展,如果我们需要的内存不够了,并且内存不能扩展了,那么就会报OOM了。引用java虚拟机规范中的一段话:所有的对象实例和数据都要在堆上进行分配。比如我们通过new来创建一个对象,创建出来的对象只包含属于各自的成员变量,并不包括成员方法。因为同一个类型的不同对象拥有各自的成员变量,存储在各自的堆中,但是他们共享该类的方法,并不是每创建一个对象就把成员方法复制一次。给对象分配内存就是把一块确定大小的从堆内存中划分出来,一般有两种方式:

①指针碰撞法:假设堆中内存是完整的,已分配的内存和空闲内存分别在不同的一侧,

通过一个指针作为分界点,需要分配内存时,仅仅需要把指针往空闲的一端移动与对象大小相等的距离。②空闲列表法:事实上,Java堆的内存并不是完整的,已分配的内存和空闲内存相互交错,JVM通过维护一个列表,记录可用的内存块信息,当需要分配内存时,从列表中找到一个足够大的内存块分配给对象实例,并更新列表上的记录。然而

创建是一个非常频繁的行为,进行堆内存分配时还需要考虑多线程并发问题,可能出现正在给对象A分配内存,指针或记录还未更新,对象B又同时分配到原来的内存,解决这个问题有两种方案:1、采用CAS保证数据更新操作的原子性;2、把内存分配按照线程进行划分,在不同的空间中进行,每个线程在Java堆中预先分配一个内存块,称为本地线程分配缓冲(Thread Local Allocation Buffer, TLAB)。在堆中分配的内存,是由java虚拟机管理回收的。在堆中产生一个对象或数组,在栈中我们可以写多个不同的引用变量指向他,那么我们多个引用相当于指向了堆内存中的同一个内存地址,那么我们用“==”作比较时,就会返回true。我们的引用变量在栈区中分配,当程序执行完我们的某个引用变量时,我们的引用变量便会自动释放,而他指向的堆区的对象不会被回收或者说不会被马上回收,而是在后续的某个不确定的时刻GC去检查该对象还有没有被引用,如果没有被引用才会回收所占内存区域。这也是java比较占内存的一个原因。

2.Java栈区

由上图可知,栈区是线程私有的,也就是说,每一个线程都会对应一个自己的栈区,生命周期也线程相同,栈中只保存基础数据类型的对象和自定义对象的引用(不是对象),也就是指针,对象都存放在堆区中,每个栈中的数据(原始类型和对象引用)都是私有的,其他栈不能访问。虚拟机栈描述的是Java方法执行的内存模型:每个线程在执行一个方法时会创建一个对应的栈帧(Stack Frame),栈帧负责存储局部变量变量表、操作数栈、动态链接和方法返回地址等信息。每个方法的调用过程,相当于栈帧在Java 栈的入栈和出栈过程。当在一段代码块定义一个变量时,Java就在栈中为这个变量分配内存空间,当该变量退出该作用域后,Java会自动释放掉为该变量所分配的内存空间,该内存空间可以立即被另作他用。Java的数学计算是在内存栈里操作的。

3.方法区

方法区也是线程共享的区域,用于存储已经被虚拟机加载的类信息,常量,静态变量和即时编译器(JIT)编译后的代码等数据。Java虚拟机把方法区描述为堆的一个逻辑分区,不过方法区有一个别名Non-Heap(非堆),用于区别于Java堆区。方法区包含所有的class和static变量。运行时常量池是方法区的一部分,Class文件中除了有类的版本,字段,方法,接口等信息以外,还有一项信息是常量池用于存储编译器生成的各种字面量和符号引用,这部分信息将在类加载后存放到方法区的运行时常量池中。Java

虚拟机对类的每一部分(包括常量池)都有严格的规定,每个字节用于存储哪种数据都必须有规范上的要求,这样才能够被虚拟机认可,装载和执行。一般来说,除了保存Class文件中描述的符号引用外,还会把翻译出来的直接引用也存储在运行时常量池中。运行时常量池相对于Class文件常量池的另外一个重要特征是具备动态性,Java虚拟机并不要求常量只能在编译期产生,也就是并非预置入Class文件常量池的内容才能进入方法区的运行时常量池中,运行期间也可将新的常量放入常量池中。常量池是方法区的一部分,所以受到内存的限制,当无法申请到足够内存时会抛出OutOfMemoryError异常。

4.本地方法栈

本地方法栈和虚拟机栈基本类似,只不过Java虚拟机栈执行的是Java代码(字节码),本地方法栈中执行的是本地方法的服务。本地方法栈中也会抛出StackOverflowError 和OutOfMemory异常。

5.程序计数器

程序计数器是线程私有的,每个线程都有独立的指令计数器,计数器记录着虚拟机正在执行的字节码指令的地址,分支、循环、跳转、异常处理和线程恢复等操作都依赖

这个计数器完成。如果线程执行的是native方法,这个计数器则为空。java虚拟机的多线程是通过轮流切换并分配处理器执行时间来完成,一个处理器同一时间只会执行一条线程中的指令。为了线程恢复后能够恢复正确的执行位置,每条线程都需要一个独立的程序计数器,以确保线程之间互不影响。所以程序计数器是“线程私有”的内存。如果虚拟机正在执行的是一个Java方法,则计数器指定的是字节码指令对应的地址,如果正在执行的是一个本地方法,则计数器指定问空undefined。程序计数器区域是Java虚拟机中唯一没有定义OutOfMemory异常的区域。

到这里我们的java内存分区就说完了,那么我们从网上摘一个例子给大家加深一下理解,如下程序代码:

上图左侧为程序内存分部情况,右边为代码及执行情况,当代码执行到右边代码红点处时,内存共进行了如下三步操作(就不自己写了,前人总结的已经很好了):

1.JVM自动寻找main方法,执行第一句代码,创建一个Test类的实例,在栈中分配一块内存,存放一个指向堆区对象的引用变量(指针110925),java中的引用变量就是C 语言中指针的一个包装,所以引用变量中存放的还是堆内存中对象的地址。

2.创建一个int型的变量date,由于是基本类型,直接在栈中存放date对应的值9。

3.创建两个BirthDate类的实例d1、d2,在栈中分别存放了对应的指针指向各自的对象。他们在实例化时调用了有参数的构造方法,因此对象中有自定义初始值。

代码继续向下走:

调用test对象的change1方法,并且以date为参数。JVM读到这段代码时,检测到i

是局部变量,因此会把i放在栈中,并且把date的值赋给i。

把1234赋给i。很简单的一步。

change1方法执行完毕,立即释放局部变量i所占用的栈空间。

调用test对象的change2方法,以实例d1为参数。JVM检测到change2方法中的b参数为局部变量,立即加入到栈中,由于是引用类型的变量,所以b中保存的是d1中的指针,此时b和d1指向同一个堆中的对象。在b和d1之间传递是指针。

change2方法中又实例化了一个BirthDate对象,并且赋给b。在内部执行过程是:在堆区new了一个对象,并且把该对象的指针保存在栈中的b对应空间,此时实例b不再指向实例d1所指向的对象,但是实例d1所指向的对象并无变化,这样无法对d1造成任何影响。

change2方法执行完毕,立即释放局部引用变量b所占的栈空间,注意只是释放了栈空间,堆空间要等待自动回收。

调用test实例的change3方法,以实例d2为参数。同理,JVM会在栈中为局部引用变量b分配空间,并且把d2中的指针存放在b中,此时d2和b指向同一个对象。再调用实例b的setDay方法,其实就是调用d2指向的对象的setDay方法。

调用实例b的setDay方法会影响d2,因为二者指向的是同一个对象。

change3方法执行完毕,立即释放局部引用变量b。

通过以上一个在实际代码中运行的例子,相信大家对堆栈的内存分配有了更加深刻的理解。

下边我们了解一下基本类型和基本类型的包装类的一写关于常量池的知识:基本类型有:byte、short、char、int、long、boolean。基本类型的包装类分别是:Byte、Short、Character、Integer、Long、Boolean。注意区分大小写。二者的区别是:基本类型体现在程序中是普通变量,基本类型的包装类是类,体现在程序中是引用变量。因此二者在内存中的存储位置不同:基本类型存储在栈中,而基本类型包装类存储在堆中。上边提到的这些包装类都实现了常量池技术,而两种浮点数类型的包装类则没有实现。另外,String类型也实现了常量池技术。

举例帮大家理解:

public class test {

public static void main(String[] args) {

objPoolTest();

}

public static void objPoolTest() {

int i = 40;

int i0 = 40;

Integer i1 = 40;

Integer i2 = 40;

Integer i3 = 0;

Integer i4 = new Integer(40);

Integer i5 = new Integer(40);

Integer i6 = new Integer(0);

Double d1=1.0;

Double d2=1.0;

//在java中对于引用变量来说“==”就是判断这两个引用变量所引用的是不是同一个对象

System.out.println("i==i0\t" + (i == i0));

System.out.println("i1==i2\t" + (i1 == i2));

System.out.println("i1==i2+i3\t" + (i1 == i2 + i3));

System.out.println("i4==i5\t" + (i4 == i5));

System.out.println("i4==i5+i6\t" + (i4 == i5 + i6));

System.out.println("d1==d2\t" + (d1==d2));

System.out.println();

}

}

运行结果如下:

i==i0 true

i1==i2 true

i1==i2+i3 true

i4==i5 false

i4==i5+i6 true

d1==d2 false

分析一下上述结果:

1.i和i0均是普通类型(int)的变量,所以数据直接存储在栈中,而栈有一个很重要的特性:栈中的数据可以共享。当我们定义了int i = 40;,再定义int i0 = 40;这时候会自动检查栈中是否有40这个数据,如果有,i0会直接指向i的40,不会再添加一个新的40。

2.i1和i2均是引用类型,在栈中存储指针,因为Integer是包装类。由于Integer包装类实现了常量池技术,因此i1、i2的40均是从常量池中获取的,均指向同一个地址,因此i1==12。

3.很明显这是一个加法运算,Java的数学运算都是在栈中进行的,Java会自动对i1、i2进行拆箱操作转化成整型,因此i1在数值上等于i2+i3。

4.i4和i5均是引用类型,在栈中存储指针,因为Integer是包装类。但是由于他们各自都是new出来的,因此不再从常量池寻找数据,而是从堆中各自new一个对象,然后各自保存指向对象的指针,所以i4和i5不相等,因为他们所存地址不同,所引用到的对象不同。

5.这也是一个加法运算,和3同理。

6.d1和d2均是引用类型,在栈中存储指针,因为Double是包装类。但Double包装类没有实现常量池技术,因此Doubled1=1.0;相当于Double d1=new Double(1.0);,是从堆new一个对象,d2同理。因此d1和d2存放的指针不同,指向的对象不同,所以不相等。

注意:

1.以上提到的几种基本类型包装类均实现了常量池技术,但他们维护的常量仅仅是【-128至127】这个范围内的常量,如果常量值超过这个范围,就会从堆中创建对象,不再从常量池中取。比如,把上边例子改成Integer i1 = 400; Integer i2 = 400;,很明显超过

了127,无法从常量池获取常量,就要从堆中new新的Integer对象,这时i1和i2就不相等了。

2.String类型也实现了常量池技术,但是稍微有点不同。String型是先检测常量池中有没有对应字符串,如果有,则取出来;如果没有,则把当前的添加进去。

下边是String的几个例子:

String a = "a1";

String b = "a" + 1;

System.out.println((a == b)); //result = true

String a = "atrue";

String b = "a" + "true";

System.out.println((a == b)); //result = true

String a = "a3.4";

String b = "a" + 3.4;

System.out.println((a == b)); //result = true

分析:JVM对于字符串常量的"+"号连接,将程序编译期,JVM就将常量字符串的"+"连接优化为连接后的值,拿"a" + 1来说,经编译器优化后在class中就已经是a1。在编译期其字符串常量的值就确定下来,故上面程序最终的结果都为true。

String a = "ab";

String bb = "b";

String b = "a" + bb;

System.out.println((a == b)); //result = false

分析:JVM对于字符串引用,由于在字符串的"+"连接中,有字符串引用存在,而引用的值在程序编译期是无法确定的,即"a" + bb无法被编译器优化,只有在程序运行期来动态分配并将连接后的新地址赋给b。所以上面程序的结果也就为false。

String a = "ab";

final String bb = "b";

String b = "a" + bb;

System.out.println((a == b)); //result = true

分析:和[3]中唯一不同的是bb字符串加了final修饰,对于final修饰的变量,它在编译时被解析为常量值的一个本地拷贝存储到自己的常量池中或嵌入到它的字节码流中。所以此时的"a" + bb和"a" + "b"效果是一样的。故上面程序的结果为true。

String a = "ab";

final String bb = getBB();

String b = "a" + bb;

System.out.println((a == b)); //result = false

private static String getBB() {

return "b";

}

分析:JVM对于字符串引用bb,它的值在编译期无法确定,只有在程序运行期调用方法后,将方法的返回值和"a"来动态连接并分配地址为b,故上面程序的结果为false。

到现在为止,相信您对java虚拟机内存分配有了一个新的了解,这篇文章到此就结束了,谢谢大家的关注。

RAM工作原理

RAM工作原理 实际的存储器结构由许许多多的基本存储单元排列成矩阵形式,并加上地址选择及读写控制等逻辑电路构成。当CPU要从存储器中读取数据时,就会选择存储器中某一地址,并将该地址上存储单元所存储的内容读走。 早期的DRAM的存储速度很慢,但随着内存技术的飞速发展,随后发展了一种称为快速页面模式(Fast Page Mode)的DRAM技术,称为FPDRAM。FPM内存的读周期从DRAM阵列中某一行的触发开始,然后移至内存地址所指位置的第一列并触发,该位置即包含所需要的数据。第一条信息需要被证实是否有效,然后还需要将数据存至系统。一旦发现第一条正确信息,该列即被变为非触发状态,并为下一个周期作好准备。这样就引入了“等待状态”,因为在该列为非触发状态时不会发生任何事情(CPU必须等待内存完成一个周期)。直到下一周期开始或下一条信息被请求时,数据输出缓冲区才被关闭。在快页模式中,当预测到所需下一条数据所放位置相邻时,就触发数据所在行的下一列。下一列的触发只有在内存中给定行上进行顺序读操作时才有良好的效果。 从50纳秒FPM内存中进行读操作,理想化的情形是一个以6-3-3-3形式安排的突发式周期(6个时钟周期用于读取第一个数据元素,接下来的每3个时钟周期用于后面3个数据元素)。第一个阶段包含用于读取触发行列所需要的额外时钟周期。一旦行列被触发后,内存就可以用每条数据3个时钟周期的速度传送数据了。 FP RAM虽然速度有所提高,但仍然跟不上新型高速的CPU。很快又出现了EDO RAM和SDRAM等新型高速的内存芯片。 介绍处理器高速缓存的有关知识 所谓高速缓存,通常指的是Level 2高速缓存,或外部高速缓存。L2高速缓存一直都属于速度极快而价格也相当昂贵的一类内存,称为SRAM(静态RAM),用来存放那些被CPU频繁使用的数据,以便使CPU不必依赖于速度较慢的DRAM。 最简单形式的SRAM采用的是异步设计,即CPU将地址发送给高速缓存,由缓存查找这个地址,然后返回数据。每次访问的开始都需要额外消耗一个时钟周期用于查找特征位。这样,异步高速缓存在66MHz总线上所能达到的最快响应时间为3-2-2-2,而通常只能达到4-2-2-2。同步高速缓存用来缓存传送来的地址,以便把按地址进行查找的过程分配到两个或更多个时钟周期上完成。SRAM在第一个时钟周期内将被要求的地址存放到一个寄存器中。在第二个时钟周期内,SRAM把数据传送给CPU。由于地址已被保存在一个寄存器中,所以接下来同步SRAM就可以在CPU读取前一次请求的数据同时接收下一个数据地址。这样,同步SRAM 可以不必另花时间来接收和译码来自芯片集的附加地址,就“喷出”连续的数据元素。优化的响应时间在66MHz总线上可以减小为2-1-1-1。 另一种类型的同步SRAM称为流水线突发式(pipelined burst)。流水线实际上是增加了一个用来缓存从内存地址读取的数据的输出级,以便能够快速地访问从内存中读取的连续数据,而省去查找内存阵列来获取下一数据元素过程中的延迟。流水线对于顺序访问模式,如高速缓存的行填充(linefill)最为高效。 什么是ECC内存 ECC是Error Correction Coding或Error Cheching and Correcting的缩写,它代表具有自动纠错功能的内存。目前的ECC存储器一般只能纠正一位二进制数的错误。 Intel公司的82430HX芯片组可支持ECC内存,所以采用82430HX芯片的主板一般都可以安装使用ECC 内存,由于ECC内存成本比较高,所以它主要应用在要求系统运算可靠性比较高的商业计算机

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新生代,正常情况下新创建的对象会被分配到新生代,但如果对象占据的内存足够大以致超过了新生代的容量限 制,也可能被分配到老年代;新生代对象的一个特点是最 新、且生命周期不长,被回收的可能性高;

全面教你认识内存参数

全面教你认识内存参数 内存热点 Jany 2010-4-28

内存这样小小的一个硬件,却是PC系统中最必不可少的重要部件之一。而对于入门用户来说,可能从内存的类型、工作频率、接口类型这些简单的参数的印象都可能很模糊的,而对更深入的各项内存时序小参数就更摸不着头脑了。而对于进阶玩家来说,内存的一些具体的细小参数设置则足以影响到整套系统的超频效果和最终性能表现。如果不想当菜鸟的话,虽然不一定要把各种参数规格一一背熟,但起码有一个基本的认识,等真正需要用到的时候,查起来也不会毫无概念。 内存种类 目前,桌面平台所采用的内存主要为DDR 1、DDR 2和DDR 3三种,其中DDR1内存已经基本上被淘汰,而DDR2和DDR3是目前的主流。 DDR1内存 第一代DDR内存 DDR SDRAM 是 Double Data Rate SDRAM的缩写,是双倍速率同步动态随机存储器的意思。DDR内存是在SDRAM内存基础上发展而来的,仍然沿用SDRAM生产体系,因此对于内存厂商而言,只需对制造普通SDRAM 的设备稍加改进,即可实现DDR内存的生产,可有效的降低成本。 DDR2内存 第二代DDR内存

DDR2 是 DDR SDRAM 内存的第二代产品。它在 DDR 内存技术的基础上加以改进,从而其传输速度更快(可达800MHZ ),耗电量更低,散热性能更优良。 DDR3内存 第三代DDR内存 DDR3相比起DDR2有更低的工作电压,从DDR2的1.8V降落到1.5V,性能更好更为省电;DDR2的4bit 预读升级为8bit预读。DDR3目前最高能够1600Mhz的速度,由于目前最为快速的DDR2内存速度已经提升到800Mhz/1066Mhz的速度,因而首批DDR3内存模组将会从1333Mhz的起跳。 三种类型DDR内存之间,从内存控制器到内存插槽都互不兼容。即使是一些在同时支持两种类型内存的Combo主板上,两种规格的内存也不能同时工作,只能使用其中一种内存。 内存SPD芯片 内存SPD芯片

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.

JVM调优总结

JVM调优总结(一)-- 一些概念 数据类型 Java虚拟机中,数据类型可以分为两类:基本类型和引用类型。基本类型的变量保存原始值,即:他代表的值就是数值本身;而引用类型的变量保存引用值。―引用值‖代表了某个对象的引用,而不是对象本身,对象本身存放在这个引用值所表示的地址的位置。 基本类型包括:byte,short,int,long,char,float,double,Boolean,returnAddress 引用类型包括:类类型,接口类型和数组。 堆与栈 堆和栈是程序运行的关键,很有必要把他们的关系说清楚。 栈是运行时的单位,而堆是存储的单位。 栈解决程序的运行问题,即程序如何执行,或者说如何处理数据;堆解决的是数据存储的问题,即数据怎么放、放在哪儿。

在Java中一个线程就会相应有一个线程栈与之对应,这点很容易理解,因为不同的线程执行逻辑有所不同,因此需要一个独立的线程栈。而堆则是所有线程共享的。栈因为是运行单位,因此里面存储的信息都是跟当前线程(或程序)相关信息的。包括局部变量、程序运行状态、方法返回值等等;而堆只负责存储对象信息。 为什么要把堆和栈区分出来呢?栈中不是也可以存储数据吗? 第一,从软件设计的角度看,栈代表了处理逻辑,而堆代表了数据。这样分开,使得处理逻辑更为清晰。分而治之的思想。这种隔离、模块化的思想在软件设计的方方面面都有体现。 第二,堆与栈的分离,使得堆中的内容可以被多个栈共享(也可以理解为多个线程访问同一个对象)。这种共享的收益是很多的。一方面这种共享提供了一种有效的数据交互方式(如:共享内存),另一方面,堆中的共享常量和缓存可以被所有栈访问,节省了空间。 第三,栈因为运行时的需要,比如保存系统运行的上下文,需要进行地址段的划分。由于栈只能向上增长,因此就会限制住栈存储内容的能力。而堆不同,堆中的对象是可以根据需要动态增长的,因此栈和堆的拆分,使得动态增长成为可能,相应栈中只需记录堆中的一个地址即可。 第四,面向对象就是堆和栈的完美结合。其实,面向对象方式的程序与以前结构化的程序在执行上没有任何区别。但是,面向对象的引入,使得对待问题的思考方式发生了改变,而更接近于自然方式的思考。当我们把对象拆开,你会发现,对象的属性其实就是数据,存放在堆中;而对象的行为(方法),就是运行逻辑,放在栈中。我们在编写对象的时候,其实即编写了数据结构,也编写的处理数据的逻辑。不得不承认,面向对象的设计,确实很美。 在Java中,Main函数就是栈的起始点,也是程序的起始点。 程序要运行总是有一个起点的。同C语言一样,java中的Main就是那个起点。无论什么java程序,找到main就找到了程序执行的入口:) 堆中存什么?栈中存什么? 堆中存的是对象。栈中存的是基本数据类型和堆中对象的引用。一个对象的大小是不可估计的,或者说是可以动态变化的,但是在栈中,一个对象只对应了一个4btye的引用(堆栈分离的好处:))。 为什么不把基本类型放堆中呢?因为其占用的空间一般是1~8个字节——需要空间比较少,而且因为是基本类型,所以不会出现动态增长的情况——长度固定,因此栈中存储就够了,如果把他存在堆中是没有什么意义的(还会浪费空间,后面说明)。可以这么说,基本类型和对象的引用都是存放在栈中,而且都是几个字节的一个数,因此在程序运行时,他们的处理方式是统一的。但是基本类型、对象引用和对象本身就有所区别了,因为一个是栈中的数据一个是堆中的数据。最常见的一个问题就是,Java中参数传递时的问题。

java内存屏障与JVM并发详解

深入Java底层:内存屏障与JVM并发详解(1) 本文介绍了内存屏障对多线程程序的影响,同时将研究内存屏障与JVM并发机制的关系,如易变量(volatile)、同步(synchronized)和原子条件式(atomic conditional)。 AD:内存屏障,又称内存栅栏,是一组处理器指令,用于实现对内存操作的顺序限制。本文假定读者已经充分掌握了相关概念和Java内存模型,不讨论并发互斥、并行机制和原子性。内存屏障用来实现并发编程中称为可见性(visibility)的同样重要的作用。 关于JVM更多内容,请参阅:JVM详解 Java虚拟机原理与优化 内存屏障为何重要? 对主存的一次访问一般花费硬件的数百次时钟周期。处理器通过缓存(caching)能够从数量级上降低内存延迟的成本这些缓存为了性能重新排列待定内存操作的顺序。也就是说,程序的读写操作不一定会按照它要求处理器的顺序执行。当数据是不可变的,同时/或者数据限制在线程范围内,这些优化是无害的。 如果把这些优化与对称多处理(symmetric multi-processing)和共享可变状态(shared mutable state)结合,那么就是一场噩梦。当基于共享可变状态的内存操作被重新排序时,程序可能行为不定。一个线程写入的数据可能被其他线程可见,原因是数据写入的顺序不一致。适当的放置内存屏障通过强制处理器顺序执行待定的内存操作来避免这个问题。 内存屏障的协调作用 内存屏障不直接由JVM暴露,相反它们被JVM插入到指令序列中以维持语言层并发原语的语义。我们研究几个简单Java程序的源代码和汇编指令。首先快速看一下Dekker算法中的内存屏障。该算法利用volatile变量协调两个线程之间的共享资源访问。 请不要关注该算法的出色细节。哪些部分是相关的?每个线程通过发信号试图进入代码第一行的关键区域。如果线程在第三行意识到冲突(两个线程都要访问),通过turn变量的操作来解决。在任何时刻只有一个线程可以访问关键区域。 1. // code run by first thread // code run by second thread 2. 3. 1 intentFirst = true; intentSecond = true;

DDR系列内存详解及硬件设计规范-Michael

D D R 系列系列内存内存内存详解及硬件详解及硬件 设计规范 By: Michael Oct 12, 2010 haolei@https://www.sodocs.net/doc/8215030670.html,

目录 1.概述 (3) 2.DDR的基本原理 (3) 3.DDR SDRAM与SDRAM的不同 (5) 3.1差分时钟 (6) 3.2数据选取脉冲(DQS) (7) 3.3写入延迟 (9) 3.4突发长度与写入掩码 (10) 3.5延迟锁定回路(DLL) (10) 4.DDR-Ⅱ (12) 4.1DDR-Ⅱ内存结构 (13) 4.2DDR-Ⅱ的操作与时序设计 (15) 4.3DDR-Ⅱ封装技术 (19) 5.DDR-Ⅲ (21) 5.1DDR-Ⅲ技术概论 (21) 5.2DDR-Ⅲ内存的技术改进 (23) 6.内存模组 (26) 6.1内存模组的分类 (26) 6.2内存模组的技术分析 (28) 7.DDR 硬件设计规范 (34) 7.1电源设计 (34) 7.2时钟 (37) 7.3数据和DQS (38) 7.4地址和控制 (39) 7.5PCB布局注意事项 (40) 7.6PCB布线注意事项 (41) 7.7EMI问题 (42) 7.8测试方法 (42)

摘要: 本文介绍了DDR 系列SDRAM 的一些概念和难点,并分别对DDR-I/Ⅱ/Ⅲ的技术特点进行了论述,最后结合硬件设计提出一些参考设计规范。 关键字关键字::DDR, DDR, SDRAM SDRAM SDRAM, , , 内存模组内存模组内存模组, , , DQS DQS DQS, DLL, MRS, ODT , DLL, MRS, ODT , DLL, MRS, ODT Notes : Aug 30, 2010 – Added DDR III and the PCB layout specification - by Michael.Hao

内存的物理结构和工作原理

内存的物理结构和工作原理 内存也叫主存,是PC系统存放数据与指令的半导体存储器单元,也叫主存储器(Main Memory),通常分为只读存储器(ROM-Read Only Memory)、随机存储器(RAM-Red Access Memory)和高速缓存存储器(Cache)。我们平常所指的内存条其实就是RAM,其主要的作用是存放各种输入、输出数据和中间计算结果,以及与外部存储器交换信息时做缓冲之用。 下面是结构: 1、PCB板 内存条的PCB板多数都是绿色的。如今的电路板设计都很精密,所以都采用了多层设计,例如4层或6层等,所以PCB板实际上是分层的,其内部也有金属的布线。理论上6层PCB板比4层PCB板的电气性能要好,性能也较稳定,所以名牌内存多采用6层PCB板制造。因为PCB板制造严密,所以从肉眼上较难分辩PCB板是4层或6层,只能借助一些印在PCB板上的符号或标识来断定。 2、金手指 黄色的接触点是内存与主板内存槽接触的部分,数据就是靠它们来传输的,通常称为金手指。金手指是铜质导线,使用时间长就可能有氧化的现象,会影响内存的正常工作,易发生无法开机的故障,所以可以隔一年左右时间用橡皮擦清理一下金手指上的氧化物。 3、内存芯片 内存的芯片就是内存的灵魂所在,内存的性能、速度、容量都是由内存芯片组成的。 4、内存颗粒空位 5、电容 PCB板上必不可少的电子元件就是电容和电阻了,这是为了提高电气性能的需要。电容采用贴片式电容,因为内存条的体积较小,不可能使用直立式电容,但这种贴片式电容性能一点不差,它为提高内存条的稳定性起了很大作用。 6、电阻 电阻也是采用贴片式设计,一般好的内存条电阻的分布规划也很整齐合理。7、内存固定卡缺口:内存插到主板上后,主板上的内存插槽会有两个夹子牢固的扣住内存,这个缺口便是用于固定内存用的。 8、内存脚缺口 内存的脚上的缺口一是用来防止内存插反的(只有一侧有),二是用来区分不同的内存,以前的SDRAM内存条是有两个缺口的,而DDR则只有一个缺口,不能混插。 9、SPD SPD是一个八脚的小芯片,它实际上是一个EEPROM可擦写存贮器,这的容量有256字节,可以写入一点信息,这信息中就可以包括内存的标准工作状态、速度、响应时间等,以协调计算机系统更好的工作。从PC100时代开始,PC100规准中就规定符合PC100标准的内存条必须安装SPD,而且主板也可

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

JVM调优总结:典型配置举例

JVM调优总结:典型配置举例 以下配置主要针对分代垃圾回收算法而言。 堆大小设置 年轻代的设置很关键 JVM中最大堆大小有三方面限制:相关操作系统的数据模型(32-bt还是64-bit)限制;系统的可用虚拟内存限制;系统的可用物理内存限制。32位系统下,一般限制在1.5G~2G;64为操作系统对内存无限制。在Windows Server 2003 系统,3.5G物理内存,JDK5.0下测试,最大可设置为1478m。 典型设置: java -Xmx3550m -Xms3550m -Xmn2g –Xss128k -Xmx3550m:设置JVM最大可用内存为3550M。 -Xms3550m:设置JVM促使内存为3550m。此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存。 -Xmn2g:设置年轻代大小为2G。整个堆大小=年轻代大小+ 年老代大小+ 持久代大小。持久代一般固定大小为64m,所以增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8。 -Xss128k:设置每个线程的堆栈大小。JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K。更具应用的线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右 java -Xmx3550m -Xms3550m -Xss128k -XX:NewRatio=4 -XX:SurvivorRatio=4 -XX:MaxPermSize=16m -XX:MaxTenuringThreshold=0 -XX:NewRatio=4:设置年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代)。设置为4,则年轻代与年老代所占比值为1:4,年轻代占整个堆栈的1/5 -XX:SurvivorRatio=4:设置年轻代中Eden区与Survivor区的大小比值。设置为4,则两个Survivor区与一个Eden区的比值为2:4,一个Survivor区占整个年轻代的1/6 -XX:MaxPermSize=16m:设置持久代大小为16m。 -XX:MaxTenuringThreshold=0:设置垃圾最大年龄。如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代。对于年老代比较多的应用,可以提高效率。如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活时间,增加在年轻代即被回收的概论。 回收器选择 JVM给了三种选择:串行收集器、并行收集器、并发收集器,但是串行收集器只适用于小数据量的情况,所以这里的选择主要针对并行收集器和并发收集器。默

详解内存工作原理及发展历程

详解内存工作原理及发展历程 RAM(Random Access Memory)随机存取存储器对于系统性能的影响是每个PC 用户都非常清楚的,所以很多朋友趁着现在的内存价格很低纷纷扩容了内存,希望借此来得到更高的性能。不过现在市场是多种内存类型并存的,SDRAM、DDR SDRAM、RDRAM等等,如果你使用的还是非常古老的系统,可能还需要EDO DRAM、FP DRAM(块页)等现在不是很常见的内存。 虽然RAM的类型非常的多,但是这些内存在实现的机理方面还是具有很多相同的地方,所以本文的将会分为几个部分进行介绍,第一部分主要介绍SRAM 和异步DRAM(asynchronous DRAM),在以后的章节中会对于实现机理更加复杂的FP、EDO和SDRAM进行介绍,当然还会包括RDRAM和SGRAM等等。对于其中同你的观点相悖的地方,欢迎大家一起进行技术方面的探讨。 存储原理: 为了便于不同层次的读者都能基本的理解本文,所以我先来介绍一下很多用户都知道的东西。RAM主要的作用就是存储代码和数据供CPU在需要的时候调用。但是这些数据并不是像用袋子盛米那么简单,更像是图书馆中用有格子的书架存放书籍一样,不但要放进去还要能够在需要的时候准确的调用出来,虽然都是书但是每本书是不同的。对于RAM等存储器来说也是一样的,虽然存储的都是代表0和1的代码,但是不同的组合就是不同的数据。 让我们重新回到书和书架上来,如果有一个书架上有10行和10列格子(每行和每列都有0-9的编号),有100本书要存放在里面,那么我们使用一个行的编号+一个列的编号就能确定某一本书的位置。如果已知这本书的编号87,

java虚拟机详解 免费

深入理解JVM 1 Java技术与Java虚拟机 说起Java,人们首先想到的是Java编程语言,然而事实上,Java是一种技术,它由四方面组成: Java编程语言、Java类文件格式、Java虚拟机和Java应用程序接口(Java API)。它们的关系如下图所示: 图1 Java四个方面的关系 运行期环境代表着Java平台,开发人员编写Java代码(.java文件),然后将之编译成字节码(.class文件)。最后字节码被装入内存,一旦字节码进入虚拟机,它就会被解释器解释执行,或者是被即时代码发生器有选择的转换成机器码执行。从上图也可以看出Java平台由Java虚拟机和Java应用程序接口搭建,Java 语言则是进入这个平台的通道,用Java语言编写并编译的程序可以运行在这个平台上。这个平台的结构如下图所示:

在Java平台的结构中, 可以看出,Java虚拟机(JVM) 处在核心的位置,是程序与底层操作系统和硬件无关的关键。它的下方是移植接口,移植接口由两部分组成:适配器和Java操作系统, 其中依赖于平台的部分称为适配器;JVM 通过移植接口在具体的平台和操作系统上实现;在JVM 的上方是Java的基本类库和扩展类库以及它们的API,利用Java API编写的应用程序(application) 和小程序(Java applet) 可以在任何Java平台上运行而无需考虑底层平台, 就是因为有Java虚拟机(JVM)实现了程序与操作系统的分离,从而实现了Java 的平台无关性。 那么到底什么是Java虚拟机(JVM)呢?通常我们谈论JVM时,我们的意思可能是: 1. 对JVM规范的的比较抽象的说明; 2. 对JVM的具体实现; 3. 在程序运行期间所生成的一个JVM实例。 对JVM规范的的抽象说明是一些概念的集合,它们已经在书《The Java Virtual Machine Specification》(《Java虚拟机规范》)中被详细地描述了;对JVM的具体实现要么是软件,要么是软件和硬件的组合,它已经被许多生产厂商所实现,并存在于多种平台之上;运行Java程序的任务由JVM的运行期实例单个承担。在本文中我们所讨论的Java虚拟机(JVM)主要针对第三种情况而言。它可以被看成一个想象中的机器,在实际的计算机上通过软件模拟来实现,有自己想象中的硬件,如处理器、堆栈、寄存器等,还有自己相应的指令系统。 JVM在它的生存周期中有一个明确的任务,那就是运行Java程序,因此当Java程序启动的时候,就产生JVM的一个实例;当程序运行结束的时候,该实例也跟着消失了。下面我们从JVM的体系结构和它的运行过程这两个方面来对它进行比较深入的研究。 2 Java虚拟机的体系结构 刚才已经提到,JVM可以由不同的厂商来实现。由于厂商的不同必然导致JVM在实现上的一些不同,然而JVM还是可以实现跨平台的特性,这就要归功于设计JVM时的体系结构了。 我们知道,一个JVM实例的行为不光是它自己的事,还涉及到它的子系统、存储区域、数据类型和指令这些部分,它们描述了JVM的一个抽象的内部体系结构,其目的不光规定实现JVM时它内部的体系结构,更重要的是提供了一种方式,用于严格定义实现时的外部行为。每个JVM都有两种机制,一个是装载具有合适名称的类(类或是接口),叫做类装载子系统;另外的一个负责执行包含在已装载的类或接口中的指令,叫做运行引擎。每个JVM又包括方法区、堆、Java栈、程序计数器和本地方法栈这五个部分,这几个部分和类装载机制与运行引擎机制一起组成的体系结构图为:

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没有执行对应的设置?

DRAM内存原理.

DRAM内存原理 1. 内存基础 不管你信不信,RDRAM (Rambus、DDR SDRAM甚至是EDO RAM它们在本质上讲是一样的。RDRAM、DDR RAM、SDRAM、EDO RAM都属于 DRAM(Dynamic RAM,即动态内存。所有的DRAM基本单位都是由一个晶体管和一个电容器组成。请看下图: 上图只是DRAM一个基本单位的结构示意图:电容器的状态决定了这个DRAM 单位的逻辑状态是1还是0,但是电容的被利用的这个特性也是它的缺点。一个电容器可以存储一定量的电子或者是电荷。一个充电的电容器在数字电子中被认为是逻辑上的1,而“空”的电容器则是0。电容器不能持久的保持储存的电荷,所以内存需要不断定时刷新,才能保持暂存的数据。电容器可以由电流来充电——当然这个电流是有一定限制的,否则会把电容击穿。同时电容的充放电需要一定的时间,虽然对于内存基本单位中的电容这个时间很短,只有大约0.2-0.18微秒,但是这个期间内存是不能执行存取操作的。

DRAM制造商的一些资料中显示,内存至少要每64ms刷新一次,这也就意味着内存有1%的时间要用来刷新。内存的自动刷新对于内存厂商来说不是一个难题,而关键在于当对内存单元进行读取操作时保持内存的内容不变——所以DRAM单元每次读取操作之后都要进行刷新:执行一次回写操作,因为读取操作也会破坏内存中的电荷,也就是说对于内存中存储的数据是具有破坏性的。所以内存不但要每64ms 刷新一次,每次读操作之后也要刷新一次。这样就增加了存取操作的周期,当然潜伏期也就越长。 SRAM,静态(StaticRAM不存在刷新的问题,一个SRAM基本单元包括4个晶体管和2个电阻。它不是通过利用电容充放电的特性来存储数据,而是利用设置晶体管的状态来决定逻辑状态——同CPU中的逻辑状态一样。读取操作对于SRAM不是破坏性的,所以SRAM不存在刷新的问题。 SRAM不但可以运行在比DRAM高的时钟频率上,而且潜伏期比DRAM短的多。SRAM仅仅需要2到3个时钟周期就能从CPU缓存调入需要的数据,而DRAM 却需要3到9个时钟周期(这里我们忽略了信号在CPU、芯片组和内存控制电路之间传输的时间。前面也提到了,SRAM需要的晶体管的数目是DRAM 的4倍,也就是说成本比DRAM高至少是4倍,在目前的售价SRAM每M价格大约是DRAM的8倍,是RAMBUS内存的2到3倍。不过它的极短的潜伏期和高速的时钟频率却的确可以带来更高的带宽。 结构和功能(SDRAM 内存最基本的单位是内存“细胞”——也就是我们前面展示给大家DRAM 基本单元示意图所示的部分,下面我们对这个部分通称为DRAM基本单元。每个DRAM 基本单元代表一个“位”——Bit(也就是一个比特,并且有一个由列地址和行地址定义的唯一地址。8个比特组成一个字节,它可代表256种组合(即2的八次幂,字节是内存中最小的可寻址单元。DRAM基本单元不能被单独寻址——否则现在的内存将会更加复杂,而且也没有必要。很多DRAM基本单元连接到同一个列线(Row line和同一个行线(Column line,组成了一个矩阵结构,这个矩阵结构就是一个Bank。大部

JVM内存大小配置方式

JVM内存大小配置方式 By:sheagle@https://www.sodocs.net/doc/8215030670.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虚拟机内存大小的配置,针对每种情况会有多种不同的配置方式,基本上都是修改配 置文件中参数的大小,无论使用哪种配置方式进行配置,只要能达到效果即可

相关主题