`
javawebsoa
  • 浏览: 409619 次
社区版块
存档分类
最新评论

【经典】用栈和堆来理解 String。好文章:String 必须要理解!!!

 
阅读更多

一、两种实例化方式:

String str =“abc”;

String str = new String("abc");

一个字符串就是String的匿名对象。

"hello".equals(str)一个字符串能够调用一个函数,可以看出,一个字符串是String的匿名对象。

二、比较

(1)直接赋值

String str =“abc”;表示一个堆内存指向给了栈内存。

直接赋值可以节省内存

举例:

  1. publicclassStringDemo01{
  2. publicstaticvoidmain(Stringargs[]){
  3. //享元模式
  4. //在堆内存中有一个"hello"的String对象,而str1和str2和str3指向这个匿名对象
  5. Stringstr1="hello";
  6. Stringstr2="hello";
  7. Stringstr3="hello";
  8. System.out.println("str1==str2-->"+(str1==str2));
  9. System.out.println("str1==str3-->"+(str1==str3));
  10. System.out.println("str2==str3-->"+(str2==str3));
  11. }
  12. }


(2)new

举例:

  1. publicclassStringDemo01{
  2. publicstaticvoidmain(Stringargs[]){
  3. Stringstr1=newString("hello");
  4. Stringstr2=newString("hello");
  5. System.out.println("str1==str2-->"+(str1==str2));
  6. }
  7. }


1.创建了"hello"的匿名String对象。

2.创建一个str的对象,并开辟新的堆空间。

3.原来的“hello”的匿名对象变成垃圾。

因此开发中最好使用直接赋值。

三、字符串的不可改变性


为什么str+="world"这种连接操作效率低,就是因为这个。

所以才会有StringBuilder或者StringBuffer。

四、String和StringBuilder的性能比较

  1. publicclassStringDemo02{
  2. publicstaticvoidmain(Stringargs[]){
  3. longbegin1=System.currentTimeMillis();
  4. Stringstr="";
  5. for(inti=0;i<10000;i++){
  6. str+=i;
  7. }
  8. longend1=System.currentTimeMillis();
  9. System.out.println("String用时:"+(end1-begin1)+"ms");//用时2000ms
  10. longbegin2=System.currentTimeMillis();
  11. StringBuildersbuilder=newStringBuilder();
  12. for(inti=0;i<10000;i++){
  13. sbuilder.append(i);
  14. }
  15. longend2=System.currentTimeMillis();
  16. System.out.println("StringBuilder用时:"+(end2-begin2)+"ms");//用时0ms,所以快了很多
  17. }
  18. }

===========================================================================================

String str=new String("x");
和String str="x";

这两句有什么区别?

在计算机的内存中有堆和栈两块空间,其中栈中存放所有对象、函数、变量等的饮用;而堆中存放对象、值等。
不管是new出的对象还是用类似String str = "x";这类的对象,都是放在堆中的。
对于你的第一个问题,举一个简单的例子:



表面上看这三句回实例化3个String对象,实际上是两个。再java中有一个叫“字符数据池”的内存管理机制,在对str2赋值之前,会检查池中有没有相同的数据,如果有,则直接引用;若没有,系统会实例化这个String的对象;而执行到String str3 = new String("x") ;系统会直接实例化该对象,而不会在池中查找。也不会将这个对象放在池中。
你可能会问,如果改动str1或str2时会不会改动另外一个引用的值。答案是不会。系统会首先在池中查找有没有相同的对象,如果没有,会实例化这个对象。

public static void main(String[] arg) {
String b = "1";
// String a=new String("a");
int c = 1;
String a = String.valueOf(c); // a!=b
// String a= String.valueOf("1"); //a=b
if (a == b) {
System.out.print("a");

}
}




http://fluagen.blog.51cto.com/146595/78018


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 = new Integer(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类,以提高程序效率。

------------------------------------------------------------------------------------------
String在栈中,StringBuffer在堆中!所以String是不可变的,数据是共享的。StringBuffer都是独占的,是可变的(因为每次都是创建新的对象!)
JAVA中都是传的引用。
我们在使用诸如String str = "abc";的格式定义类时,总是想当然地认为,我们创建了String类的对象str。担心陷阱!对象可能并没有被创建!唯一可以肯定的是,指向String类的引用被创建了。)
这里String str 是一个String类的引用,所以在用诸如swap(String str1,String str2){}之类的方法时传的都是引用。
------------------------------------------------------------------
是这样的,JAVA为了提高效率,所以对于String类型进行了特别的处理---为string类型提供了串池
定义一个string类型的变量有两种方式:
string name= "tom ";
string name =new string( "tom ")
使用第一种方式的时候,就使用了串池,
使用第二中方式的时候,就是一种普通的声明对象的方式
如果你使用了第一种方式,那么当你在声明一个内容也是 "tom "的string时,它将使用串池里原来的那个内存,而不会重新分配内存,也就是说,string saname= "tom ",将会指向同一块内存


另外关于string类型是不可改变的问题:
string类型是不可改变的,也就是说,当你想改变一个string对象的时候,比如name= "madding "
那么虚拟机不会改变原来的对象,而是生成一个新的string对象,然后让name去指向它,如果原来的那个 "tom "没有任何对象去引用它,虚拟机的垃圾回收机制将接收它。
据说这样可以提高效率!!!哈哈

----------------------------------------------------------------------------------------------------------------
public class Pass {
String a="123";

public static void test(Pass passA) {
passA.a="abc";
}
public static void main(String[] args) {
Pass passB=new Pass();
passB.a= "123";
System.out.println(passB.a);
test(passB);
System.out.println(passB.a);
}
}
结果是:
123
abc
从这个结果来看是通过引用传递的.String不是简单类型,那么是不是也是通过引用来传递呢?看下面这个例子:
public class Pass {
public static void test(String str) {
str = "World";
}
public static void main(String[] args) {
String string = "Hello";
System.out.println(string);
test(string);
System.out.println(string);
}
}
结果是:
Hello
Hello
第三个例子:
public class Pass {
public static void test(StringBuffer str) {
str.append("World");
}
public static void main(String[] args) {
StringBuffer string = new StringBuffer("Hello");
System.out.println(string);
test(string);
System.out.println(string);
}
}
结果:
Hello
HelloWorld
这我就不太明白了,既然String不是简单类型,那么它应该和对象是一样通过引用来传递的,可是结果却相反.而StringBuffer却是通过引用来传递的?
这到底是为什么?哪位帮忙解释一下.
----------------------------------------------------------------------------------


所有的参数传递都是 传值,从来没有 传引用 这个事实。(
从程序运行的角度来看,参数传递,只有传值,从不传递其它的东西。只不过,值的内容有可能是数据,也有可能是一个内存地址
程序运行的时候,使用的空间可以分为两个部分,栈和堆。栈是指运行栈,局部变量,参数,都分配在栈上。程序运行的时候,新生成的对象,都分配在堆里,堆里分配的对象,栈里的数据参数,或局部变量。
)

所有的参数传递都会在 程序运行栈上 新分配一个 值 的复制品.

楼主的第一段代码。

public static void test(Pass passA) {
passA.a="abc";
}


这个传的 PassA 的 地址值。这个 地址值 被复制了一份。
不信,你写:

public static void test(Pass passA) {
passA = null;
}


看看, 对passA有什么影响?
毫无作用。函数调用出来后,passA还是原来的值,不会变成Null.

但是,你的代码对 passA进行了操作 passA.a ,改变了passA的成员变量。
这个成员变量是一个真实指向String 的 地址,当然能够被改变。
这就是操作 (.) 和 赋值 (=) 的区别。
这是对 成员变量 a 的 赋值。真正改变了成员变量 a 的值。

注意,这里传递的参数是 passA, 而不是 a.
所以,passA 被复制了一份。passA 的这个副本的 a 变量还 指向 原来的 passA 的 a 变量。


public static void test(String str) {
str = "World";
}


只有对参数的 赋值,没有对参数的操作,当然不会产生影响。

================================================================================

栈内存

堆内存

基础类型,对象引用(堆内存地址)

由new创建的对象和数组,

存取速度快

相对于栈内存较慢

数据大小声明周期必须确定

分配的内存由java虚拟机自动垃圾回收器管理。动态分配内存大小

共享特性

栈中如果有字符串,则直接引用

如果没有,开辟新的空间存入值

每new一次在堆内存中生成一个新的对象。

创建之后值可以改变

String类声明后则不可改变

一、栈内存

基础类型int, short, long, byte, float, double, boolean, char和对象引用

栈的共享特性

String str1 = "abc";
String str2 = "abc";
System.out.println(str1==str2); //true

1、编译器先处理String str1 = "abc";它会在栈中创建一个变量为str1的引用,然后查找栈中是否有abc这个值,如果没找到,就将abc存放进来,然后将str1指向abc。

2、接着处理String str2 = "abc";在创建完b的引用变量后,因为在栈中已经有abc这个值,便将str2直接指向abc。这样,就出现了str1与str2同时均指向abc的情况。

二、堆内存

new、newarray、anewarray和multianewarray等指令建立

要注意:我们在使用诸如String str = "abc";的格式定义类时,总是想当然地认为,创建了String类的对象str。担心陷阱!对象可能并没有被创建!而可能只是指向一个先前已经创建的 对象。只有通过new()方法才能保证每次都创建一个新的对象。 由于String类的immutable性质,当String变量需要经常变换其值时,应该考虑使用StringBuffer类,以提高程序效率。

三、 ==内存地址比对

String str1 = "abc";
String str2 = "abc";
System.out.println(str1==str2); //true str1和str2同时指向 栈内存 中同一个内存空间

String str3 = "abc";
String str4 = new String("abc") ;

System.out.println(str3 == str4); //flase str3值在栈内存中,str4值在堆内存中

String hello = "hello" ;

String hel = "hel" ;

String lo = "lo" ;

System.out.println(hello == "hel" + "lo") ; //true

//两个常量相加,先检测栈内存中是否有hello如有有,指向已有的栈中的hello空间

System.out.println(hello == "hel" + lo) ; //flase

System.out.println(hello == hel + lo) ; //flase

//lo是在常量池中,不检查栈内存,在堆中产生一个新的hello

四、 equals值进行比对

public booleanequals(Object anObject)

将此字符串与指定的对象比较。当且仅当该参数不为null,并且是与此对象表示相同字符序列的String对象时,结果才为true。

String str5 = "abc";
String str6 = new String("abc") ;

System.out.println(str5.equals(str6)); //true str5的值str6的值比对

五、 intern 栈中值的内存地址

Public String intern()

当调用intern方法时

1、如果池已经包含一个等于此String对象的字符串(用equals(Object)方法确定),则返回池中的字符串。

2、将此String对象添加到池中,并返回此String对象的引用。

String s7 = new String("abc") ;

String s8 = "abc" ;

System.out.println(s7 == s7.intern()) ;//flase;

System.out.println(s8 == s7.intern() );//true

1.检查栈内存中有没有abc对象如果有

2.将s7指向pool中abc

===================================================================================================

http://sd.csdn.net/a/20120220/311988.html Java 堆内存的十个要点

导读:对于程序员来说,知道堆空间,设置堆空间,处理堆空间的outOfMemoryError错误,分析heap dump是非常重要的。文中介绍了Java堆的学习教程以及Java堆内存(heap memory)的十个要点。

文章内容如下:

我刚开始学习Java编程时,可不知道什么是堆内存或堆空间(heap space),甚至根本不管对象创建时都放在哪里去了。正式了写一些程序后,经常会遇到java.lang.outOfMemoryError等错误,我才开始关注堆内存。

对大多数程序员都经历过这样的过程,因为学习一种语言是非常容易来的,但是学习基础是非常难的,因为没有什么特定的流程让你学习编程的每个基础,使你发觉编程的秘诀。

对于程序员来说,知道堆空间,设置堆空间,处理堆空间的outOfMemoryError错误,分析heap dump是非常重要的。这个关于Java堆的教程是给我刚开始学编程的兄弟看的。如果你知道这个基础知识或者知道底层发生了什么,当然可能帮助不是那么大。除非你知道了对象被创建在堆中,否则你不会意识到OutOfMemoryError是发生在堆空间中的。我尽可能的将我所知道的所有关于堆的知识都写下来了,也希望你们能够尽可能多的贡献和分享你的知识,以便可以让其他人也受益。

Java中的堆空间是什么?

当Java程序开始运行时,JVM会从操作系统获取一些内存。JVM使用这些内存,这些内存的一部分就是堆内存。堆内存通常在存储地址的底层,向上排列。当一个对象通过new关键字或通过其他方式创建后,对象从堆中获得内存。当对象不再使用了,被当做垃圾回收掉后,这些内存又重新回到堆内存中。要学习垃圾回收,请阅读”Java中垃圾回收的工作原理”。

如何增加Java堆空间

在大多数32位机、Sun的JVM上,Java的堆空间默认的大小为128MB,但也有例外,例如在32未Solaris操作系统(SPARC平台版本)上,默认的最大堆空间和起始堆空间大小为 -Xms=3670K 和 -Xmx=64M。对于64位操作系统,一般堆空间大小增加约30%。但你使用Java 1.5的throughput垃圾回收器,默认最大的堆大小为物理内存的四分之一,而起始堆大小为物理内存的十六分之一。要想知道默认的堆大小的方法,可以用默认的设置参数打开一个程序,使用JConsole(JDK 1.5之后都支持)来查看,在VM Summary页面可以看到最大的堆大小。

用这种方法你可以根据你的程序的需要来改变堆内存大小,我强烈建议采用这种方法而不是默认值。如果你的程序很大,有很多对象需要被创建的话,你可以用-Xms and -Xmx这两个参数来改变堆内存的大小。Xms表示起始的堆内存大小,Xmx表示最大的堆内存的大小。另外有一个参数 -Xmn,它表示new generation(后面会提到)的大小。有一件事你需要注意,你不能任意改变堆内存的大小,你只能在启动JVM时设定它。

堆和垃圾回收

我们知道对象创建在堆内存中,垃圾回收这样一个进程,它将已死对象清除出堆空间,并将这些内存再还给堆。为了给垃圾回收器使用,堆主要分成三个区域,分别叫作New Generation,Old Generation或叫Tenured Generation,以及Perm space。New Generation是用来存放新建的对象的空间,在对象新建的时候被使用。如果长时间还使用的话,它们会被垃圾回收器移动到Old Generation(或叫Tenured Generation)。Perm space是JVM存放Meta数据的地方,例如类,方法,字符串池和类级别的详细信息。你可以查看“Java中垃圾回收的工作原理”来获得更多关于堆和垃圾回收的信息。

java

Java堆中的OutOfMemoryError错误

当JVM启动时,使用了-Xms 参数设置的对内存。当程序继续进行,创建更多对象,JVM开始扩大堆内存以容纳更多对象。JVM也会使用垃圾回收器来回收内存。当快达到-Xmx设置的最大堆内存时,如果没有更多的内存可被分配给新对象的话,JVM就会抛出java.lang.outofmemoryerror,你的程序就会当掉。在抛出 OutOfMemoryError之前,JVM会尝试着用垃圾回收器来释放足够的空间,但是发现仍旧没有足够的空间时,就会抛出这个错误。为了解决这个问题,你需要清楚你的程序对象的信息,例如,你创建了哪些对象,哪些对象占用了多少空间等等。你可以使用profiler或者堆分析器来处理 OutOfMemoryError错误。”java.lang.OutOfMemoryError: Java heap space”表示堆没有足够的空间了,不能继续扩大了。”java.lang.OutOfMemoryError: PermGen space”表示permanent generation已经装满了,你的程序不能再装在类或者再分配一个字符串了。

Java Heap dump

Heap dump是在某一时间对Java堆内存的快照。它对于分析堆内存或处理内存泄露和Java.lang.outofmemoryerror错误是非常有用的。在JDK中有一些工具可以帮你获取heap dump,也有一些堆分析工具来帮你分析heap dump。你可以用“jmap”来获取heap dump,它帮你创建heap dump文件,然后,你可以用“jhat”(堆分析工具)来分析这些heap dump。

Java堆内存(heap memory)的十个要点:

1. Java堆内存是操作系统分配给JVM的内存的一部分。

2. 当我们创建对象时,它们存储在Java堆内存中。

3. 为了便于垃圾回收,Java堆空间分成三个区域,分别叫作New Generation, Old Generation或叫作Tenured Generation,还有Perm Space。

4. 你可以通过用JVM的命令行选项 -Xms, -Xmx, -Xmn来调整Java堆空间的大小。不要忘了在大小后面加上”M”或者”G”来表示单位。举个例子,你可以用 -Xmx256m来设置堆内存最大的大小为256MB。

5. 你可以用JConsole或者 Runtime.maxMemory(), Runtime.totalMemory(), Runtime.freeMemory()来查看Java中堆内存的大小。

6. 你可以使用命令“jmap”来获得heap dump,用“jhat”来分析heap dump。

7. Java堆空间不同于栈空间,栈空间是用来储存调用栈和局部变量的。

8. Java垃圾回收器是用来将死掉的对象(不再使用的对象)所占用的内存回收回来,再释放到Java堆空间中。

9. 当你遇到java.lang.outOfMemoryError时,不要紧张,有时候仅仅增加堆空间就可以了,但如果经常出现的话,就要看看Java程序中是不是存在内存泄露了。

10. 请使用Profiler和Heap dump分析工具来查看Java堆空间,可以查看给每个对象分配了多少内存。











分享到:
评论

相关推荐

    Java堆、栈和常量池

    对于字符串:其对象的引用都是存储在栈中的,如果是编译期已经创建好(直接用双引号定义的)的就存储在常量池中,如果是运行期(new出来的)才能确定的就存储在堆中.对于equals相等的字符串,在常量池中永远只有一份,在堆...

    javascript typeof id===’string’?document.getElementById(id):id解释 原创

    看完了上面的文章再看下面的就比较好理解了 一般来说常用的函数代码 function $(id){ return typeof id==='string'?document.getElementById(id):id;} var GetBy = function (id) { return "string" == typeof id...

    详解C#中的string与String

    本篇文章主要对jC#中的小写string与大写String进行详细介绍,相信对大家学习会有很好的帮助,需要的朋友一起来看下吧

    springmybatis

    其实还有更简单的方法,而且是更好的方法,使用合理描述参数和SQL语句返回值的接口(比如IUserOperation.class),这样现在就可以至此那个更简单,更安全的代码,没有容易发生的字符串文字和转换的错误.下面是详细...

    值类型和引用类型的区别

    上面这段代码,我们首先创建了一个Person类,包含了Name和Age两个属性,毋庸置疑,Person类是引 用类型,Name也是,因为它是string类型的(但string是很特殊的引用类型,后面将专门有一篇文章来讨论),但Age则是值...

    在一小时内学会 C#(txt版本)

    对 C++ 来说,前面例子中 Date 类的属性就是 day、month 和 year,而你添加了 Get 和 Set 方法。C# 提供了一种更加便捷、简单而又直接的属性访问方式。 所以上面的类应该写成这样: 复制内容到剪贴板 代码: using ...

    golang如何自定义json序列化应用详解

    下面这篇文章主要介绍了关于golang自定义json序列化应用的相关内容,下面话不多说了,来一起看看详细的介绍吧 问题引入 当某个struct存在某个字段为string或者[]byte类型但是实际上保存的内容是json格式的数据时,...

    二十三种设计模式【PDF版】

    有经验的面向对象设计者会告诉你,要一下子就得到复用性和灵活性好的设计, 即使不是不可能的至少也是非常困难的。一个设计在最终完成之前常要被复用好几次,而且每一次都有所修改。 有经验的面向对象设计者的确能...

    判断2个字符串是否含有相同的字符

    (关于空间的占用,如果要用一个和字符串a一样长的数组counter来计录a中各起点对应与b最大重合子字符串,这个数组也要和a一样长,空间上也不合适,除非情形很特殊,a短b长,不然不如直接malloc()一个堆空间来储存...

    java8源码-ToBeABestJavaer:我要把java一顿暴学!!!!

    java8 源码 点击关注及时获取笔主最新更新文章,并可免费领取本文档配套的《Java面试突击》以及Java工程师必备学习资源。 作者的其他开源项目推荐: : 适合新手入门以及有经验的开发人员查阅的 ...(String和

    Java中的String不再纠结

    string的种种,纠结,希望这篇文章让大家不再纠结。。 string是我们经常用到的一个类型,其实有时候觉得写程序是在反复的操作字符串,这是C的特点,在java中,jdk很好的封装了关于字符串的操作。主要讲的是三个类...

    十天学会ASP.net--我认为ASP.NET比ASP难很多,希望大家做好准备

    但是我觉得如果大家ASP不会,还是先看一下【十天学会ASP教程】,大家所需要了解的不是ASP的程序怎么写,而是怎么构建服务器,怎么使用HTML表单,同时对SQL语句有一个基础和理解,因为在本文里我不会将将一些基础的...

    linux vi 常用命令

    %s/string/replace/c:同样会将全文的string字符串取代为replace字符串,和上面指令不同的地方是,%s和1,$s是相同的功能, c则是表示要替代之前必须再次确认是否取代。 1,20s/string/replace/g:将1至20行间的...

    不再纠结Java中的String类

    string的种种,纠结,希望这篇文章让大家不再纠结。。  String是我们经常用到的一个类型,其实有时候觉得写程序是在反复的操作字符串,这是C的特点,在java中,jdk很好的封装了关于字符串的操作。主要讲的是三个...

    WeChatImg-使用kotlin写一个仿微信点击图片浏览的效果.zip

    看看这篇文章)到这里之前都很好理解,关键就是adapter和点击图片跳转的代码在API 21以后,我们可以使用内置的Activity切换动画。但是这样也就意味着只能兼容5.0之后的系统,ActivityOptions是一个静态类,它提供了...

    hihocoder和leetcode-leetcode:leetcode

    hihocoder和leetcode leetcode 目录名 功能 Array 数组 Backtracking 回溯 Bit_Manipulation 位操作 Design 数据结构设计 Divide_and_Conquer 分而治之 DP 动态规划 Hash_Table 哈希表 List 链表 Math 数学 Stack 栈...

    Ajax中responseText返回的是一个页面而不是一个值

    自己在struts2中的写好了业务逻辑用response返回的内容却是一个页面的! 然后就去了百度一下,说的是将struts2的返回值设为null(return null),这是因为struts2返回的是一个页面。如果在action中只进行业务逻辑不...

    用C++实现简单的文件IO操作

     为了使用下面的方法, 你必须包含头文件(译者注:在标准C++中,已经使用取 代,所有的C++标准头文件都是无后缀的。)。这是 的一个扩展集, 提供有缓 冲的文件输入输出操作. 事实上, &lt;iostream.h&gt; 已经被包含了, ...

    从实例谈面向对象编程、工厂模式和重构

    为了更好的理解设计思想,实例尽可能简单化。但随着需求的增加,程序将越来越复杂。此时就有修改设 计的必要,重构和设计模式就可以派上用场了。最后当设计渐趋完美后,你会发现,即使需求不断增加, 你也可以神清气...

Global site tag (gtag.js) - Google Analytics