没有储备足够的堆空间对象占堆中的空间问题,怎么解决

Java中堆与栈的区别(仅做个人知识储备) - CSDN博客
Java中堆与栈的区别(仅做个人知识储备)
中堆与栈的区别
简单的说: Java把内存划分成两种:一种是栈内存,一种是堆内存。
在函数中定义的一些基本类型的变量和对象的引用变量都在函数的栈内存中分配。 当在一段代码块定义一个变量时,Java就在栈中为这个变量分配内存空间,当超过变量的作用域后,Java会自动释放掉为该变量所分配的内存空间,该内存空间可以立即被另作他用。
&&&& 堆内存用来存放由new创建的对象和数组。
&&&&&在堆中分配的内存,由Java虚拟机的自动垃圾回收器来管理。
1. 栈(stack)与堆(heap)都是Java用来在Ram中存放数据的地方。与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆。
2. 栈的优势是,存取速度比堆要快,仅次于直接位于CPU中的寄存器。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。另外,栈数据可以共享,详见第3点。堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于要在运行时动态分配内存,存取速度较慢。
3. Java中的数据类型有两种。 一种是基本类型(primitive types), 共有8种,即int, short, long, byte, float, double, boolean, char(注意,并没有string的基本类型)。这种类型的定义是通过诸如int a = 3; long b = 255L;的形式来定义的,称为自动变量。值得注意的是,自动变量存的是字面值,不是类的实例,即不是类的引用,这里并没有类的存在。如int a = 3; 这里的a是一个指向int类型的引用,指向3这个字面值。这些字面值的数据,由于大小可知,生存期可知(这些字面值固定定义在某个程序块里面,程序块退出后,字段值就消失了),出于追求速度的原因,就存在于栈中。
另外,栈有一个很重要的特殊性,就是存在栈中的数据可以共享。假设我们同时定义
&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与 b的值后,再令a=4;那么,b不会等于4,还是等于3。在编译器内部,遇到a=4;时,它就会重新搜索栈中是否有4的字面值,如果没有,重新开辟地址存放4的值;如果已经有了,则直接将a指向这个地址。因此a值的改变不会影响到b的值。
另一种是包装类数据,如Integer, String, Double等将相应的基本数据类型包装起来的类。这些类数据全部存在于堆中,Java用new()语句来显式地告诉编译器,在运行时才根据需要动态创建,因此比较灵活,但缺点是要占用更多的时间。
4. String是一个特殊的包装类数据。即可以用String str = new String(&abc&);的形式来创建,也可以用String str = &abc&;的形式来创建(作为对比,在JDK 5.0之前,你从未见过Integer i = 3;的表达式,因为类与字面值是不能通用的,除了String。而在JDK 5.0中,这种表达式是可以的!因为编译器在后台进行Integer i =&Integer.valueOf(3);&的转换)。前者是规范的类的创建过程,即在Java中,一切都是对象,而对象是类的实例,全部通过new()的形式来创建。Java
中的有些类,如DateFormat类,可以通过该类的getInstance()方法来返回一个新创建的类,似乎违反了此原则。其实不然。该类运用了单例模式来返回类的实例,只不过这个实例是在该类内部通过new()来创建的,而getInstance()向外部隐藏了此细节。那为什么在String str = &abc&;中,并没有通过new()来创建实例,
是不是违反了上述原则?其实没有。
5. 关于String str = &abc&的内部工作。Java内部将此语句转化为以下几个步骤:
(1)先定义一个名为str的对String类的对象引用变量:String str;
(2)在栈中查找有没有存放值为&abc&的地址,如果没有,则开辟一个存放字面值为&abc&的地址,接着创建一个新的String类的对象o,并将o 的字符串值指向这个地址,而且在栈中这个地址旁边记下这个引用的对象o。如果已经有了值为&abc&的地址,则查找对象o,并返回o的地址。
(3)将str指向对象o的地址。 值得注意的是,一般String类中字符串值都是直接存值的。但像String str = &abc&;这种场合下,其字符串值却是保存了一个指向存在栈中数据的引用! 为了更好地说明这个问题,我们可以通过以下的几个代码进行验证。
String str1 = &abc&; String str2 = &abc&;
System.out.println(str1==str2); //true
&注意,我们这里并不用str1.equals(str2);的方式,因为这将比较两个字符串的值是否相等。==号,根据JDK的说明,只有在两个引用都指向了同一个对象时才返回真值。而我们在这里要看的是,str1与str2是否都指向了同一个对象。 结果说明,JVM创建了两个引用str1和str2,但只创建了一个对象,而且两个引用都指向了这个对象。 我们再来更进一步,将以上代码改成:
String str1 = &abc&;
String str2 = &abc&;
str1 = &bcd&;
System.out.println(str1 + &,& + str2); //bcd, abc
System.out.println(str1==str2); //false
这就是说,赋值的变化导致了类对象引用的变化,str1指向了另外一个新对象!而str2仍旧指向原来的对象。上例中,当我们将str1的值改为&bcd&时,JVM发现在栈中没有存
放该值的地址,便开辟了这个地址,并创建了一个新的对象,其字符串的值指向这个地址。
事实上,String类被设计成为不可改变(immutable)的类。如果你要改变其值,可以,但JVM在运行时根据新值悄悄创建了一个新对象,然后将这个对象的地址返回给原来类的引用。这个创建过程虽说是完全自动进行的,但它毕竟占用了更多的时间。在对时间要求比较敏感的环境中,会带有一定的不良影响。 再修改原来代码:
String str1 = &abc&;
String str2 = &abc&;
str1 = &bcd&;
String str3 = str1;
System.out.println(str3); //bcd
String str4 = &bcd&;
System.out.println(str1 == str4); //true
str3 这个对象的引用直接指向str1所指向的对象(注意,str3并没有创建新对象)。当str1改完其值后,再创建一个String的引用str4,并指向因str1修改值而创建的新的对象。可以发现,这回str4也没有创建新的对象,从而再次实现栈中数据的共享。 我们再接着看以下的代码。
String str1 = new String(&abc&);
String str2 = &abc&;
System.out.println(str1==str2); //false
创建了两个引用。创建了两个对象。两个引用分别指向不同的两个对象。
String str1 = &abc&;
String str2 = new String(&abc&);
&System.out.println(str1==str2); //false
创建了两个引用。创建了两个对象。两个引用分别指向不同的两个对象。 以上两段代码说明,只要是用new()来新建对象的,都会在堆中创建,而且其字符串是单独存值的,即使与栈中的数据相同,也不会与栈中的数据共享。
6. 数据类型包装类的值不可修改。不仅仅是String类的值不可修改,所有的数据类型
包装类都不能更改其内部的值。
7. 结论与建议:
(1)我们在使用诸如String str = &abc&;的格式定义类时,总是想当然地认为,我们创建了String类的对象str。担心陷阱!对象可能并没有被创建!唯一可以肯定的是,指向 String类的引用被创建了。至于这个引用到底是否指向了一个新的对象,必须根据上下文来考虑,除非你通过new()方法来显要地创建一个新的对象。因此,更为准确的说法是,我们创建了一个指向String类的对象的引用变量str,这个对象引用变量指向了某个值为&abc&的String类。清醒地认识到这一点对排除程序中难以发现的bug是很有帮助的。
(2)使用String str = &abc&;的方式,可以在一定程度上提高程序的运行速度,因为JVM会自动根据栈中数据的实际情况来决定是否有必要创建新对象。而对于String str = new String(&abc&);的代码,则一概在堆中创建新对象,而不管其字符串值是否相等,是否有必要创建新对象,从而加重了程序的负担。这个思想应该是享元模式的思想,但JDK的内部在这里实现是否应用了这个模式,不得而知。
(3)当比较包装类里面的数值是否相等时,用equals()方法;当两个包装类的引用是否指向同一个对象时,用==。
(4)由于String类的immutable性质,当String变量需要经常变换其值时,应该考虑使用StringBuffer类,以提高程序效率。
java中内存分配策略及堆和栈的比较
内存分配策略
按照编译原理的观点,程序运行时的内存分配有三种策略,分别是静态的,栈式的,和堆式的.
静态存储分配是指在编译时就能确定每个数据目标在运行时刻的存储空间需求,因而在
编译时就可以给他们分配固定的内存空间.这种分配策略要求程序代码中不允许有可变(比如可变数组)的存在,也不允许有嵌套或者递归的结构出现,因为它们都会导致编译程序无法计算准确的存储空间需求.
栈式存储分配也可称为动态存储分配,是由一个类似于堆栈的运行栈来实现的.和静态存储分配相反,在栈式存储方案中,程序对数据区的需求在编译时是完全未知的,只有到运行的时候才能够知道,但是规定在运行中进入一个程序模块时,必须知道该程序模块所需的数据区大小才能够为其分配内存.和我们在数据结构所熟知的栈一样,栈式存储分配按照先进后出的原则进行分配。
静态存储分配要求在编译时能知道所有变量的存储要求,栈式存储分配要求在过程的入口处必须知道所有的存储要求,而堆式存储分配则专门负责在编译时或运行时模块入口处都无法确定存储要求的数据结构的内存分配,比如可变长度串和对象实例.堆由大片的可利用块或空闲块组成,堆中的内存可以按照任意顺序分配和释放.
堆和栈的比较
上面的定义从编译原理的教材中总结而来,除静态存储分配之外,都显得很呆板和难以理解,下面撇开静态存储分配,集中比较堆和栈:
从堆和栈的功能和作用来通俗的比较,堆主要用来存放对象的,栈主要是用来执行程序的.而这种不同又主要是由于堆和栈的特点决定的:
在编程中,例如C/C++中,所有的方法调用都是通过栈来进行的,所有的局部变量,形式参数都是从栈中分配内存空间的。实际上也不是什么分配,只是从栈顶向上用就行,就好像工厂中的传送带(conveyor belt)一样,Stack Pointer会自动指引你到放东西的位置,你所要做的只是把东西放下来就行.退出函数的时候,修改栈指针就可以把栈中的内容销毁.这样的模式速度最快,当然要用来运行程序了.需要注意的是,在分配的时候,比如为一个即将要调用的程序模块分配数据区时,应事先知道这个数据区的大小,也就说是虽然分配是在程序运行时进行的,但是分配的大小多少是确定的,不变的,而这个&大小多少&是在编译时确定的,不是在运行时.
堆是应用程序在运行的时候请求分配给自己内存,由于从操作系统管理的内存分配,所以在分配和销毁时都要占用时间,因此用堆的效率非常低.但是堆的优点在于,编译器不必知道要从堆里分配多少存储空间,也不必知道存储的数据要在堆里停留多长的时间,因此,用堆保存数据时会得到更大的灵活性。事实上,面向对象的多态性,堆内存分配是必不可少的,因为多态变量所需的存储空间只有在运行时创建了对象之后才能确定.在C++中,要求创建一个对象时,只需用
new命令编制相关的代码即可。执行这些代码时,会在堆里自动进行数据的保存.当然,为达到这种灵活性,必然会付出一定的代价:在堆里分配存储空间时会花掉更长的时间!这也正是导致我们刚才所说的效率低的原因,看来列宁同志说的好,人的优点往往也是人的缺点,人的缺点往往也是人的优点(晕~).
JVM中的堆和栈
JVM是基于堆栈的虚拟机.JVM为每个新创建的线程都分配一个堆栈.也就是说,对于一个Java程序来说,它的运行就是通过对堆栈的操作来完成的。堆栈以帧为单位保存线程的状态。JVM对堆栈只进行两种操作:以帧为单位的压栈和出栈操作。 我们知道,某个线程正在执行的方法称为此线程的当前方法.我们可能不知道,当前方法使用的帧称为当前帧。当线程激活一个Java方法,JVM就会在线程的 Java堆栈里新压入一个帧。这个帧自然成为了当前帧.在此方法执行期间,这个帧将用来保存参数,局部变量,中间计算过程和其他数据.这个帧在这里和编译原理中的活动纪录的概念是差不多的.
从Java的这种分配机制来看,堆栈又可以这样理解:堆栈(Stack)是操作系统在建立某个进程时或者线程(在支持多线程的操作系统中是线程)为这个线程建立的存储区域,该区域具有先进后出的特性。 每一个Java应用都唯一对应一个JVM实例,每一个实例唯一对应一个堆。应用程序在运行中所创建的所有类实例或数组都放在这个堆中,并由应用所有的线程 共享.跟C/C++不同,Java中分配堆内存是自动初始化的。Java中所有对象的存储空间都是在堆中分配的,但是这个对象的引用却是在堆栈中分配,也就是说在建立一个对象时从两个地方都分配内存,在堆中分配的内存实际建立这个对象,而在堆栈中分配的内存只是一个指向这个堆对象的指针(引用)而已。
Java为什么慢?JVM的存在当然是一个原因,但有人说,在Java中,除了简单类型(int,char等)的数据结构,其它都是在堆中分配内存(所以说Java的一切都是对象),这也
是程序慢的原因之一。
我的想法是(应该说代表TIJ的观点),如果没有Garbage Collector(GC),上面的说法就是成立的.堆不象栈是连续的空间,没有办法指望堆本身的内存分配能够象堆栈一样拥有传送带般的速度,因为,谁会 为你整理庞大的堆空间,让你几乎没有延迟的从堆中获取新的空间呢?
这个时候,GC站出来解决问题.我们都知道GC用来清除内存垃圾,为堆腾出空间供程序使用,但GC同时也担负了另外一个重要的任务,就是要让Java中堆的内存分配和其他语言中堆栈的内存分配一样快,因为速度的问题几乎是众口一词的对Java的诟病.要达到这样的目的,就必须使堆的分配也能够做到象传送带一样,不用自己操心去找空闲空间.这样,GC除了负责清除Garbage外,还要负责整理堆中的对象,把它们转移到一个远离Garbage的纯净空间中无间隔的排列起来,就象堆栈中一样紧凑,这样Heap Pointer就可以方便的指向传送带的起始位置,或者说一个未使用的空间,为下一个需要分配内存的对象&指引方向&.因此可以这样说,垃圾收集影响了对象的创建速度,听起来很怪,对不对?
&那GC怎样在堆中找到所有存活的对象呢?前面说了,在建立一个对象时,在堆中分配实际建立这个对象的内存,而在堆栈中分配一个指向这个堆对象的指针(引 用),那么只要在堆栈(也有可能在静态存储区)找到这个引用,就可以跟踪到所有存活的对象.找到之后,GC将它们从一个堆的块中移到另外一个堆的块中,并 将它们一个挨一个的排列起来,就象我们上面说的那样,模拟出了一个栈的结构,但又不是先进后出的分配,而是可以任意分配的,在速度可以保证的情况下, Isn't it great?
&但是,列宁同志说了,人的优点往往也是人的缺点,人的缺点往往也是人的优点(再晕~~).GC()的运行要占用一个线程,这本身就是一个降低程序运行性能 的缺陷,更何况这个线程还要在堆中把内存翻来覆去的折腾.不仅如此,如上面所说,堆中存活的对象被搬移了位置,那么所有对这些对象的引用都要重新赋值.这 些开销都会导致性能的降低.
基础数据类型直接在栈空间分配,方法的形式参数,直接在栈空间分配,当方法调用完成后从栈空间回收。引用数据类型,需要用new来创建,既在栈空间 分配一个地址空间,又在堆空间分配对象的类变量 。方法的引用参数,在栈空间分配一个地址空间,并指向堆空间的对象区,当方法调用完成后从栈空间回收。局部变量new出来时,在栈空间和堆空间中分配空 间,当局部变量生命周期结束后,栈空间立刻被回收,堆空间区域等待GC回收。方法调用时传入的literal参数,先在栈空间分配,在方法调用完成后从栈 空间分配。字
符串常量在DATA区域分配,this在堆空间分配。数组既在栈空间分配数组名称,又在堆空间分配数组实际的大小!
JVM中的堆和栈
JVM是基于堆栈的虚拟机。JVM为每个新创建的线程都分配一个堆栈。也就是说,对于一个Java程序来说,它的运行就是通过对堆栈的操作来完成的。堆栈以帧为单位保存线程的状态。JVM对堆栈只进行两种操作:以帧为单位的压栈和出栈操作。 我们知道,某个线程正在执行的方法称为此线程的当前方法。我们可能不知道,当前方法使用的帧称为当前帧。当线程激活一个Java方法,JVM就会在 线程的Java堆栈里新压入一个帧。这个帧自然成为了当前帧.在此方法执行期间,这个帧将用来保存参数,局部变量,中间计算过程和其他数据。这个帧在这里
和编译原理中的活动纪录的概念是差不多的。 从Java的这种分配机制来看,堆栈又可以这样理解:堆栈(Stack)是操作系统在建立某个进程时或者线程(在支持多线程的操作系统中是线程)为这个线程建立的存储区域,该区域具有先进后出的特性。
每一个Java应用都唯一对应一个JVM实例,每一个实例唯一对应一个堆。应用程序在运行中所创建的所有类实例或数组都放在这个堆中,并由应用所有 的线程共享。跟C/C++不同,Java中分配堆内存是自动初始化的。Java中所有对象的存储空间都是在堆中分配的,但是这个对象的引用却是在堆栈中分 配,也就是说在建立一个对象时从两个地方都分配内存,在堆中分配的内存实际建立这个对象,而在堆栈中分配的内存只是一个指向这个堆对象的指针(引用)而已。
本文已收录于以下专栏:
相关文章推荐
1、C++指针问题:
2、堆排序问题:
3、C语言变量存储在内存的地方:
4、程序调优方法:
5、Linux文件:
6、有int型变量a和b,在不引入新的变量的情况下,实现变量a和b的交换。
1、C++创建对象:
2、条件概率:
3、随机插入和删除操作性能好的数据结构:
4、C++初始化列表:
5、系统调用和库函数的区别:
6、Linux两个进程打开同一个文件:
7、进程间通信:
8、并发...
1、有文件上传的时候,是无法用ajax动态提交的,只能用form表单提交。所以要想做到当前页面不跳转的话,你可以在页面中放一个隐藏的iframe。
把 form表单的 target属性设置成   这个...
Java基础知识 最能考验专业Java从业人员的水平,夯实基础,走到哪里都潇洒
说到字符串String 就会想起字符char 我们可以把String类型看成是 由char类型数据组成的一个数组char[],其实java系统内部也就是这么定义的,由于String太实用了,所以这种类...
剑指Offer——知识点储备-故障检测、性能调优与Java类加载机制故障检测、性能调优用什么工具可以查出内存泄露
(1)MerroyAnalyzer:一个功能丰富的java堆转储文件分析工具,可以帮助...
1、MySQL导入导出数据库操作:
2、关系模型(数据库)的完整性:
3、强类型语言和弱类型语言、动态类型语言和静态类型语言:
4、一条SQL语句的执行顺序:
5、DDL、DCL、DQL、DML:
接口(interface)是什么?“接口(interface)是用来描述类具有什么功能,而并不给出每个功能的具体实现。一个类可以实现(implement)一个或多个接口,并在需要接口的地方,随时使用实...
Q:我想知道用工厂作为参数到底比直接用接口作为参数好在哪里。在调用把工厂作为参数的方法时,虽然不用指明实现接口的类,但是要指明实现工厂的类,并没有提高代码的重用性啊。请大家指点。
A1:工厂...
他的最新文章
讲师:宋宝华
讲师:何宇健
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)solaris下的tomcat遇到“java.io.IOException: 没有足够的空间”的问题 - CSDN博客
solaris下的tomcat遇到“java.io.IOException: 没有足够的空间”的问题
solaris下的tomcat遇到&java.io.IOException: 没有足够的空间&的问题
[案例]:java.io.IOException: 没有足够的空间 [发送央视命令线程] DEBUG cdm.GlobalCAHelper& - -----------------生成摘要:925c10d20d5faafd2a6c20a0& 32&&&&&&& at java.lang.UNIXProcess.forkAndExec(Native Method)&&&&&&& at java.lang.UNIXProcess.&init&(UNIXProcess.java:52)&&&&&&& at java.lang.Runtime.execInternal(Native Method)&&&&&&& at java.lang.Runtime.exec(Runtime.java:566)&&&&&&& at java.lang.Runtime.exec(Runtime.java:428)&&&&&&& at java.lang.Runtime.exec(Runtime.java:364)&&&&&&& at java.lang.Runtime.exec(Runtime.java:326)&&&&&&& at com.onewaveinc.cetus.business.util.DVBUtil.runcmd(DVBUtil.java:1179)&&&&&&& at com.onewaveinc.cetus.business.external.PreBillingTask.preBillingByAccountId(PreBillingTask.java:63)&&&&&&& at com.onewaveinc.cetus.business.external.AppExternalBridge.preBillingByAccountId(AppExternalBridge.java:117)&&&&&&& at com.onewaveinc.cetus.business.external.AppExternalBridge.preBillingByApp(AppExternalBridge.java:103)&&&&&&& at com.onewaveinc.cetus.business.external.AppExternalBridge.sendMessage(AppExternalBridge.java:45)&&&&&&& at com.onewaveinc.cetus.util.ldapaccess.send.LdapSendThread.preBilling(LdapSendThread.java:143)&&&&&&& at com.onewaveinc.cetus.util.ldapaccess.send.LdapSendThread.process(LdapSendThread.java:92)&&&&&&& at com.onewaveinc.cetus.util.ldapaccess.send.LdapSendThread.run(LdapSendThread.java:67)
问题分析(此处是引用网络上的信息)在solaris环境上运行JAVA程序时,JVM的堆内存设置应小于总虚拟内存的50%,实际上最好小于30%,如果超过50%则系统中所有使用到Runtime.exec这种创建子进程java.lang.Process的操作都将失败。创建子进程会复制一份父进程的内存,如果交换内存不够则会出现IO异常:java.io.IOException: 没有足够的空间 15:58:03,126 ERROR [STDERR]& at java.lang.UNIXProcess.forkAndExec(Native Method) 15:58:03,127 ERROR [STDERR]& at java.lang.UNIXProcess.&init&(UNIXProcess.java:52) 15:58:03,128 ERROR [STDERR]& at java.lang.Runtime.execInternal(Native Method) 15:58:03,129 ERROR [STDERR]& at java.lang.Runtime.exec(Runtime.java:573)
JDK相关故障为:7230。&&
内容(此处是官方文档解释):Bug ID:& 5049299& Votes& 20& Synopsis& (process) Use posix_spawn, not fork, on S10 to avoid swap exhaustion& Category& java:classes_lang& Reported Against& b06 , 1.4.2_04& Release Fixed&& State& In progress, request for enhancement& Related Bugs& 6381152 , 4343908 , 4391042& Submit Date& 18-MAY-2004& Description& If you run a &small& program (e.g., a Perl script) from a &big& Java process ona machine with &moderate& free swap space (but not as much as the big Javaprocess), then Runtime.exec() fails.&Work Around& 1) mkfile followed by swap -a to add more swap space2) do Runtime.exec &early& in the application execution before the process has&& grown so large (i.e. so the transient swap requirement between Runtime.exec's&&& fork and exec calls is big), cache resulting Process object, then replace&& the &later& Runtime.exec calls that kicked off perl with println or the like&&&& to direct the aforementioned process exec perl with the same command line&& and relay back the perl command's standard output and error traffic.3) Like (2) but spawn the &exec daemon& separate from Java to avoid any use of&& Runtime.exec and instead communicate with Java via a pipe or socket to && initiate running the perl scripts. && exit status.
& && &Evaluation& Solaris reserves swap space conservatively, so when an X-megabyte processforks the kernel attempts to reserve an additional X MB of swap space just incase the child actually does touch all those pages, thereby making privatecopies, and then later needs to swap them out.& (Linux doesn't do this, sothis bug will not be reproducible on a Linux system.)
Within the constraints of the existing semantics of Runtime.exec there doesnot appear to be any way to avoid this in current Solaris releases.& vfork(2)is not thread-safe and popen(3C) only provides access to one of the child'sstandard streams rather than all three of them.& S10 does support the newposix_ we should look into using that when running on S10.
See the comments section for additional information.
--&& && I agree that the use of posix_spawn on S10 should be investigated.Historically, changes to this kind of code has been extraordinarily riskydue to unforseen race conditions, so this sort of change should be introducednear the beginning of a release.& Therefore I am targeting this at dolphin.Hopefully, it will get addressed early in that release.Posted Date :
18:03:11.0
我的分析:根据以上的描述,可知是由于交换分区不够导致的;由于solaris沿用了老的分区方式,对swap默认分区还是以旧的分区规则进行分配大小。linux已经改正了这个bug
增加交换分区命令:mkfile 500m swapfileswap -a swapfile
其他相关命令:swap -l: 列出当前交换分区情况swap -a /data/swapfile: 添加交换分区文件,注意:后面跟的文件名需要以绝对路径来执行。
相关参考文档:
Solaris性能监控的Swap空间管理
 随着电子商务如火如荼的开展,网站服务器的性能变得尤其重要。一旦服务器的能力不能满足用户的需要,就会对用户的服务大打折扣,那么就需要对服务器进行升级扩容。但是,有些时候只需对服务器进行一些适当的性能调整,便可以越过性能的瓶颈,大大提高服务器的吞吐能力,从而减少服务器升级的费用。
  本文介绍了在Solaris平台上Swap(交换)空间的基本概念、实现的原理以及对Swap(交换)空间进行监控的方法和调整的策略。
  什么是SWAP(交换)空间
  对于一般的Solaris系统管理员来说,很少会接触Swap(交换)空间,在他们看来Swap区只不过是磁盘上的一两个分区或是几个Swap(交换)文件,当系统没有足够的物理内存来处理当前进程的时候,就利用Swap(交换)空间作为虚拟内存的临时存储空间,这种说法从技术角度来说是没有错的,但Solaris在实现Swap时有其非常独特的地方。
  SWAP空间作用
  众所周知,现代操作系统都实现了&虚拟内存&这一技术,不但在功能上突破了物理内存的限制,使程序可以操纵大于实际物理内存的空间,更重要的是&虚拟内存&是隔离每个进程的安全保护网,使每个进程不受其他程序的干扰。
  Swap空间的作用可简单描述为:当系统的物理内存不够用的时候,就需要将物理内存中的一部分空间释放出来,以供当前运行的程序使用。那些被释放的空间可能来自一些很长时间没有什么操作的程序,这些被释放的空间被临时保存到Swap空间中,等到那些程序要运行时,再从Swap中恢复保存的数据到内存中。这样,系统总是在物理内存不够时,才进行Swap交换。这种现象对于计算机使用者是经常遇到的。
  有一点要声明的是,并不是所有从物理内存中交换出来的数据都会被放到Swap中(如果这样的话,Swap会不堪重负),有相当一部分的数据直接交换到文件系统。例如,有的程序会打开一些文件,对文件进行读写(其实每个程序都至少打开一个文件,那就是运行程序本身),当这些程序的内存空间需要交换出去时,文件部分的数据就没有必要放到Swap空间中了,如果是读文件操作,那么内存数据直接就释放了,不需要交换出来,因为下次需要时,直接从文件系统就能恢复;如果是写文件,只需要将变化的数据保存到文件中,以便恢复。但是那些用malloc(3C)和new函数生成的对象的数据则不同,需要Swap空间,因为它们在文件系统中没有相应的&储备&文件,因此被称为&匿名&(Anonymous)的内存数据,这类数据还包括堆栈中的一些状态和变量数据等,所以说,Swap空间是&匿名&数据的交换空间。
  Swap的配置对性能的影响
  太多的Swap空间会浪费磁盘的空间,而太少的Swap空间,系统则会发生错误。
  如果系统的物理内存用光了,你的系统就会跑得慢,但仍能运行;如果Swap空间用光了,那么系统就会发生错误。例如,Web服务器能根据不同的请求数量衍生出多个服务进程(或线程),如果Swap空间用完,则服务进程无法进动,通常会出现&application is out of memory&的错误,严重时会造成服务进程的死锁。因此Swap空间的分配是很重要的。
  通常情况下,Swap空间应大于或等于物理内存的大小,最小不应小于64M,通常Swap空间的大小应是物理内存的2-2.5倍(Solaris 2以上的版本有所变化,见下文)。但根据不同的应用,应有不同的配置:如果是小的桌面系统,只需要较小的Swap空间,而大的服务器系统则视情况不同需要不同大小的Swap空间。特别是数据库服务器和Web服务器会随着访问量的增加,对Swap 空间的要求也会增加,具体配置参见各自服务器产品的说明。
  另外,Swap分区的数量对性能也有很大的影响。因为Swap交换的操作是磁盘I/O的操作,如果有多个Swap交换区,Swap空间的分配会以轮流的方式操作于所有的Swap,这样会大大均衡I/O的负载,加快Swap交换的速度。如果只有一个交换区,所有的交换操作会使交换区变得很忙,使系统大多数时间位于等待状态,效率很低,用性能监视工具就会发现,此时的CPU并不很忙,而系统却慢,这说明,瓶颈在I/O上,依靠提高CPU的速度是解决不了问题的。
  性能监视
  Swap空间的分配固然很重要,而系统在运行时的性能监控却更加有价值,通过性能监视工具可以检查系统的各项性能指标,找到系统性能的瓶颈。本文只介绍一下在Solaris下和Swap相关的一些命令和用途。
  最常用的是Vmstat命令,在大多数Unix平台下都有此命令,此命令可以查看大多数性能的指标。
  另外使用swap -s 也能简单的查看当前swap资源的使用情况。例如:   # swap -s   total: 65896k bytes allocated + 56840k reserved = 122736k used,   1069456k available
  能够方便的看出swap空间的已用和未用资源的大小。应该使Swap保持30%的负载以下,才能保证系统的良好性能。
  Solaris中Swap的特点
  虚拟Swap空间
  本来Swap空间就是为虚拟内存服务的,现在Solaris的Swap空间也成为虚拟,这到底是怎么回事呢?
  让我们看一个例子就明白了,当在Solaris 2以前版本的Solaris(或其它Unix, 如Linux)上编程时经常会出现一个问题:
  假设系统当前还有可用的内存空间为30M,而只剩下10M的Swap空间了,这时,如果有一个进程开始运行并企图执行Malloc(15*)的命令(分配15M空间),这个进程会因为这个命令而失败。
  为什么呢?系统不是有30M可用的内存空间吗?原因在于:你的Swap空间不足,系统认为你在分配空间以后,没有能力(空间)在发生页面交换时,将这部分数据保存起来,因此认为你没有资格分配这块空间。这不是太不公平了吧!也许这15M空间根本不用交换,当前系统可是还有30M内存空间的富余啊!
  还有更不公平的呢?有些大型系统配备了海量的内存,1G或4G,配了这么多内存就是为了避免交换,提高运行速度,可是系统还要为这个系统分配并不需要的Swap空间,占用了大量磁盘资源。
  为了弥补这个缺陷,Sun为Solaris 2 以后的版本设计了虚拟Swap空间。所谓虚拟的Swap空间,概念其实很简单,swap空间再也不是单指硬盘的分区或文件。虚拟Swap空间包含两个部分:部分物理内存和传统上的Swap分区。经过适当的配置,可以使系统需要Swap空间时,先使用内存部分的swap空间,如果内存部分的swap空间不够,再使用磁盘部分的Swap空间。这样,也许你硬盘上的Swap空间很少得到使用了,甚至根本不需要Swap分区。
  Swap空间与TMPFS文件系统的关系
  你知道吗?虚拟Swap空间与 /tmp目录有相当大的关系。Sun在实现/tmp目录时,充分考虑了应用程序运行的效率。许多应用程序,特别是数据库服务都会频繁使用/tmp目录作为临时数据保存区,而Solaris将/tmp目录下的文件都放在内存中而不是硬盘里,这样会大大提高应用程序的效率。
  但是/tmp目录的空间是从系统虚拟空间里挤出来的,是虚拟Swap空间的一部分。如果说,你用完了/tmp空间,也就是用完了Swap空间,所以要小心监视系统的/tmp目录的使用情况,千万别用光了,否则系统会瘫痪!下面两点建议作为参考:
  1.在Mount /tmp目录时,使用(-o Size)选项来控制/tmp目录的大小。
  2.当使用编译器编译文件时,如果不想占用Swap空间,则用TMPDIR环境变量指向另外一个临时目录,而不是/tmp目录。
  有关Swap空间操作的系统命令
  增加Swap空间
  1.成为超级用户 $su - root
  2.创建Swap文件 #mkfile nnn[klblm] filename   如:#mkfile 100m swapfile1
  3.激活Swap文件   Swap文件必须以绝对路径来指定,filename指的是上一步创建的文件。
  4.现在新加的Swap文件已经起作用了,但系统重新启动以后,并不会记住前几步的操作。因此要在/etc/vfstab文件中记录文件的名字,和Swap类型,如: /path/filename - - Swap - no -
  5.效验Swap文件是否加上 /usr/sbin/swap -l
  删除多余的Swap空间
  1.成为超级用户
  2.使用swap -d 命令收回swap空间。   #/usr/sbin/swap -d /path/filename
  3.编辑/etc/ufstab文件,去掉此Swap(交换)文件的实体。
  4.从文件系统中回收此文件。   #rm swap-filename
  5.当然,如果此Swap(交换)空间不是一个文件,而是一个分区,则需创建一个新的文件系统,再挂接到原来的文件系统上。
本文已收录于以下专栏:
相关文章推荐
程序启动报java.io.IOException: No space left on device (errno:28)。说明磁盘空间不足。
1.df -k,发现程序所在的工作目录/data,居...
在某重要客户生产环境上遇到这个问题。在对某系统做升级的时候,该系统需要从服务器上获取升级需要的文件,然后解压,再进行升级操作。操作过程就遇到了这个奇怪的问题。
在这里服务器管理着几十台这样类似的系统...
目前android上的绝大多数项目还是由JAVA开发的,而java最常见的异常之一就是java.io.IOException,这个异常我们在android开发中也会经常遇到,这里整理了一些在A...
现象我们前面做完了namenode format之后,用./start-all.sh 重启之后jps检查发现slave机子的datanode没有启动起来。如图:少了datanode。进入日志路径查看日...
java.io.IOException: Connection reset by peer
        at sun.nio.ch.FileDispatcherImpl.read0(Native...
Tomcat启动时出现IOException while loading persisted sessions: java.io.EOFException异常
Tomcat启动时出现如下异常问题...
- IOException while loading persisted sessions: java.io.EOFException
java.io.EOFException
    at&#...
错误代码如下:
严重: IOException while loading persisted sessions: java.io.EOFException
java.io.EOFException
- IOException while loading persisted sessions: java.io.EOFException
java.io.EOFException
    at j...
(1)java代码通过keystore文件获取私钥报错
使用keytool 工具生成keystore文件,然后通过java 获取私钥privateKey 时,报错:
Xml代码  
他的最新文章
讲师:宋宝华
讲师:何宇健
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)

我要回帖

更多关于 切线空间转对象空间 的文章

 

随机推荐