Javaのガベージコレクションのメカニズムので、そうOOMまで、スタックのヒープメモリの割り当てに注意を払うしない傾向があります
まず、スタックヒープの概念を理解します
図1に示すように、ストレージ・ヒープのインスタンスを作成し、[オブジェクト]
- プログラムは、JVMはOSからメモリの一部を取得し、実行を開始し、ヒープメモリの一部です。ヒープメモリは、典型的には、上方に配置された記憶アドレスの基礎となります。
- スタックは、クラスがヒープアップ空間から割り当てられたオブジェクトをインスタンス化され、「実行時」データフィールドです。
- スペースは「新しい」と他の命令の確立によってヒープに割り当てられている、ヒープが動的にメモリサイズを割り当てられ、生存率は、事前にコンパイラに指示する必要はありません。
- C ++とは異なり、Javaは自動的にスタックおよびヒープの管理、ガベージコレクタが自動的に未使用のメモリ・ヒープを再利用が可能です。
- 欠点は、実行時にメモリの動的割り当てに、ということであるので、メモリアクセスが遅いです。
図2に示すように、スタック[ストレージ]基本タイプと参照型
- 通常、パラメータ、ローカル変数を格納するための方法の最後のアウトデータ構造、;
- Javaでは、すべての基本的なタイプ(ショート、INT、長い、バイト、フロート、ダブル、ブール、文字)、および変数の参照型は、スタックに格納されています。
- 現在、一般的にスコープのスタックデータで生活空間({...}囲まれた領域によって、
- 高速CPUレジスタの真後ろに位置する反応器、よりアクセス速度スタック。
- データは、基準の複数の同一のアドレスを指すことができ、スタックを共有することができます。
- 欠点は、スタックサイズと生存率のデータは、柔軟性の欠如を決定しなければならないということです。
3、要約
- オペレーティングシステムに割り当てられているJavaヒープメモリは、JVMのメモリの一部です。
- 我々は、Javaヒープメモリに格納されているオブジェクトを作成する場合。
- あなたは、JVMコマンドラインオプション-Xms、-Xmx、-Xmnを使用してJavaヒープ領域のサイズを調整することができます。
- スタックに格納されたデータの基本タイプ:短い、int型、長い、バイト、フロート、ダブル、ブール、文字
- ちょうどそのJavaヒープメモリに保存されているの形で新しいオブジェクトを作成します。
第二に、データがスタックに保存されています
1、データストレージの基本的なタイプ
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 true
2、包装类数据存储
如Integer, Double, String等将相应的基本数据类型包装起来的类。
这些类数据全部存在于堆中,Java用new()语句来显示地告诉编译器,在运行时才根据需要动态创建,因此比较灵活,但缺点是要占用更多的时间。
以String为例
String是一个特殊的包装类数据。即可以用String str = new String("abc");的形式来创建,也可以用String str = "abc";的形式来创建。
前者是规范的类的创建过程,即在Java中,一切都是对象,而对象是类的实例,全部通过new()的形式来创建。
那为什么在String str = "abc";中,并没有通过new()来创建实例,是不是违反了上述原则?其实没有。
关于String str = "abc"的内部工作。Java内部将此语句转化为以下几个步骤:
- a、先定义一个名为str的对String类的对象引用变量:String str;
- b、在栈中查找有没有存放值为"abc"的地址,如果没有,则开辟一个存放字面值为"abc"的地址,接着创建一个新的String类的对象O,并将O的字符串值指向这个地址,而且在栈中这个地址旁边记下这个引用的对象O。如果已经有了值为"abc"的地址,则查找对象O,并返回O的地址。
- c、将str指向对象O的地址。
值得注意的是,通常String类中字符串值都是直接存值的。但像String str = "abc";这种场合下,其字符串值却是保存了一个指向存在栈中数据的引用(即:String str = "abc";既有栈存储,又有堆存储)。
为了更好地说明这个问题,我们可以通过以下的几个代码进行验证。
String str1 = "abc";
String str2 = "abc";
System.out.println(str1==str2); //true
只有在两个引用都指向了同一个对象时才返回真值。str1与str2是否都指向了同一个对象)
结果说明,JVM创建了两个引用str1和str2,但只创建了一个对象,而且两个引用都指向了这个对象。
3、总结
(1). 我们在使用诸如String str = "abc";的格式定义类时,总是想当然地认为,我们创建了String类的对象str。
担心陷阱!对象可能并没有被创建!唯一可以肯定的是,指向 String类的引用被创建了。
至于这个引用到底是否指向了一个新的对象,必须根据上下文来考虑,除非你通过new()方法来显要地创建一个新的对象。
因此,更为准确的说法是,我们创建了一个指向String类的对象的引用变量str,这个对象引用变量指向了某个值为"abc"的String类。
清醒地认识到这一点对排除程序中难以发现的bug是很有帮助的。
(2). 使用String str = "abc";的方式,可以在一定程度上提高程序的运行速度,因为JVM会自动根据栈中数据的实际情况来决定是否有必要创建新对象。
而对于String str = new String("abc");的代码,则一概在堆中创建新对象,而不管其字符串值是否相等,是否有必要创建新对象,从而加重了程序的负担。
(3). 由于String类的immutable性质(因为包装类的值不可修改),当String变量需要经常变换其值时,应该考虑使用StringBuffer类,以提高程序效率。
4、实例
String s = new String("abc") 创建了几个对象?
首先我们要明白两个概念,引用变量和对象,对象一般通过new在堆中创建,s只是一个引用变量。
答案2个。
5、知识点
我们可以用==判断一下两个引用变量是否指向了一个地址即一个对象