自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Java內(nèi)存管理方法小結(jié)

開發(fā) 后端
Java內(nèi)存管理就是對象的分配和釋放問題,分配:內(nèi)存的分配是由程序完成的,而對象的釋放是由垃圾回收機(jī)制決定和執(zhí)行的,這樣做確實(shí)簡化了程序員的工作。

這里向大家簡單介紹一下Java內(nèi)存管理的概念和方法,Java內(nèi)存管理就是對象的分配和釋放問題。首先看一下分配和釋放的概念,分配:內(nèi)存的分配是由程序完成的,程序員需要通過關(guān)鍵字new為每個對象申請內(nèi)存空間(基本類型除外),所有的對象都在堆(Heap)中分配空間;而對象的釋放是由垃圾回收機(jī)制決定和執(zhí)行的。

Java內(nèi)存管理總結(jié)

1.Java是如何管理內(nèi)存的

Java內(nèi)存管理就是對象的分配和釋放問題。
分配:內(nèi)存的分配是由程序完成的,程序員需要通過關(guān)鍵字new為每個對象申請內(nèi)存空間(基本類型除外),所有的對象都在堆(Heap)中分配空間。

釋放:對象的釋放是由垃圾回收機(jī)制決定和執(zhí)行的,這樣做確實(shí)簡化了程序員的工作。但同時(shí),它也加重了JVM的工作。這也是Java程序運(yùn)行速度較慢的原因之一。因?yàn)椋珿C為了能夠正確釋放對象,GC必須監(jiān)控每一個對象的運(yùn)行狀態(tài),包括對象的申請、引用、被引用、賦值等,GC都需要進(jìn)行監(jiān)控。

2.什么叫Java的內(nèi)存泄露

在Java內(nèi)存管理中,內(nèi)存泄漏就是存在一些被分配的對象,這些對象有下面兩個特點(diǎn),首先,這些對象是可達(dá)的,即在有向圖中,存在通路可以與其相連(也就是說仍存在該內(nèi)存對象的引用);其次,這些對象是無用的,即程序以后不會再使用這些對象。如果對象滿足這兩個條件,這些對象就可以判定為Java中的內(nèi)存泄漏,這些對象不會被GC所回收,然而它卻占用內(nèi)存。
與C++內(nèi)存泄露的區(qū)別:

Java內(nèi)存泄露與C++內(nèi)存泄露概念的區(qū)別

在C++中,內(nèi)存泄漏的范圍更大一些。有些對象被分配了內(nèi)存空間,然后卻不可達(dá),由于C++中沒有GC,這些內(nèi)存將永遠(yuǎn)收不回來。在Java中,這些不可達(dá)的對象都由GC負(fù)責(zé)回收,因此程序員不需要考慮這部分的內(nèi)存泄露。

3.JVM的內(nèi)存區(qū)域組成

Java把內(nèi)存分兩種:一種是棧內(nèi)存,另一種是堆內(nèi)存

1。在函數(shù)中定義的基本類型變量和對象的引用變量都在函數(shù)的棧內(nèi)存中分配;

2。堆內(nèi)存用來存放由new創(chuàng)建的對象和數(shù)組以及對象的實(shí)例變量

在函數(shù)(代碼塊)中定義一個變量時(shí),Java就在棧中為這個變量分配內(nèi)存空間,當(dāng)超過變量的作用域后,Java會自動釋放掉為該變量所分配的內(nèi)存空間;在堆中分配的內(nèi)存由Java虛擬機(jī)的自動垃圾回收器來管理

3。棧的優(yōu)缺點(diǎn)

堆的優(yōu)勢是可以動態(tài)分配內(nèi)存大小,生存期也不必事先告訴編譯器,因?yàn)樗窃谶\(yùn)行時(shí)動態(tài)分配內(nèi)存的。缺點(diǎn)就是要在運(yùn)行時(shí)動態(tài)分配內(nèi)存,存取速度較慢;

棧的優(yōu)勢是,存取速度比堆要快,僅次于直接位于CPU中的寄存器。另外,棧數(shù)據(jù)可以共享。但缺點(diǎn)是,存在棧中的數(shù)據(jù)大小與生存期必須是確定的,缺乏靈活性。#p#

4。Java內(nèi)存管理中數(shù)據(jù)如何存儲

a)基本數(shù)據(jù)類型

Java內(nèi)存管理中的基本數(shù)據(jù)類型共有8種,即int,short,long,byte,float,double,boolean,char(注意,并沒有string的基本類型)。這種類型的定義是通過諸如inta=3;longb=255L;的形式來定義的。如inta=3;這里的a是一個指向int類型的引用,指向3這個字面值。這些字面值的數(shù)據(jù),由于大小可知,生存期可知(這些字面值定義在某個程序塊里面,程序塊退出后,字段值就消失了),出于追求速度的原因,就存在于棧中。

另外,棧有一個很重要的特殊性,就是存在棧中的數(shù)據(jù)可以共享。
比如:我們同時(shí)定義:
inta=3;
intb=3;
編譯器先處理inta=3;首先它會在棧中創(chuàng)建一個變量為a的引用,然后查找有沒有字面值為3的地址,沒找到,就開辟一個存放3這個字面值的地址,然后將a指向3的地址。接著處理intb=3;在創(chuàng)建完b這個引用變量后,由于在棧中已經(jīng)有3這個字面值,便將b直接指向3的地址。這樣,就出現(xiàn)了a與b同時(shí)均指向3的情況。

定義完a與b的值后,再令a=4;那么,b不會等于4,還是等于3。在編譯器內(nèi)部,遇到時(shí),它就會重新搜索棧中是否有4的字面值,如果沒有,重新開辟地址存放4的值;如果已經(jīng)有了,則直接將a指向這個地址。因此a值的改變不會影響到b的值。

b)對象

在Java內(nèi)存管理中,創(chuàng)建一個對象包括對象的聲明和實(shí)例化兩步,下面用一個例題來說明對象的內(nèi)存模型。
  假設(shè)有類Rectangle定義如下:

Java代碼 

  1. classRectangle{  
  2.  
  3.   doublewidth,height;  
  4.  
  5.   Rectangle(doublew,doubleh){  
  6.  wwidth=w;  
  7. hheight=h;  
  8. }  
  9. }  
  10.  
  11. classRectangle{  
  12.  
  13.   doublewidth,height;  
  14.  
  15.   Rectangle(doublew,doubleh){  
  16.  wwidth=w;  
  17. hheight=h;  
  18. }  
  19. }  

      (1)明對象時(shí)的內(nèi)存模型

  用Rectanglerect;聲明一個對象rect時(shí),將在棧內(nèi)存為對象的引用變量rect分配內(nèi)存空間,但Rectangle的值為空,稱rect是一個空對象。空對象不能使用,因?yàn)樗€沒有引用任何“實(shí)體”。

  (2)對象實(shí)例化時(shí)的內(nèi)存模型

  當(dāng)執(zhí)行rect=newRectangle(3,5);時(shí),會做兩件事:
  在堆內(nèi)存中為類的成員變量width,height分配內(nèi)存,并將其初始化為各數(shù)據(jù)類型的默認(rèn)值;接著進(jìn)行顯式初始化(類定義時(shí)的初始化值);最后調(diào)用構(gòu)造方法,為成員變量賦值。
返回堆內(nèi)存中對象的引用(相當(dāng)于首地址)給引用變量rect,以后就可以通過rect來引用堆內(nèi)存中的對象了。

c)創(chuàng)建多個不同的對象實(shí)例

一個類通過使用new運(yùn)算符可以創(chuàng)建多個不同的對象實(shí)例,這些對象實(shí)例將在堆中被分配不同的內(nèi)存空間,改變其中一個對象的狀態(tài)不會影響其他對象的狀態(tài)。例如:

Java代碼 

  1. Rectangler1=newRectangle(3,5);  
  2. Rectangler2=newRectangle(4,6);  
  3.  
  4. Rectangler1=newRectangle(3,5);  
  5. Rectangler2=newRectangle(4,6);  
  6.  

  此時(shí),將在堆內(nèi)存中分別為兩個對象的成員變量width、height分配內(nèi)存空間,兩個對象在堆內(nèi)存中占據(jù)的空間是互不相同的。如果有:

Java代碼 

  1. Rectangler1=newRectangle(3,5);  
  2. Rectangler2=r1;  
  3.  
  4. Rectangler1=newRectangle(3,5);  
  5. Rectangler2=r1;   

 則在堆內(nèi)存中只創(chuàng)建了一個對象實(shí)例,在棧內(nèi)存中創(chuàng)建了兩個對象引用,兩個對象引用同時(shí)指向一個對象實(shí)例。#p#

d)包裝類

Java內(nèi)存管理中數(shù)據(jù)的基本型別都有對應(yīng)的包裝類:如int對應(yīng)Integer類,double對應(yīng)Double類等,基本類型的定義都是直接在棧中,如果用包裝類來創(chuàng)建對象,就和普通對象一樣了。例如:inti=0;i直接存儲在棧中。Integeri(i此時(shí)是對象)=newInteger(5);這樣,i對象數(shù)據(jù)存儲在堆中,i的引用存儲在棧中,通過棧中的引用來操作對象。

e)String

String是一個特殊的包裝類數(shù)據(jù)。可以用用以下兩種方式創(chuàng)建: 

  1. 1.Stringstr=newString("abc");  
  2. 2.Stringstr="abc"; 

第一種創(chuàng)建方式,和普通對象的的創(chuàng)建過程一樣;
第二種創(chuàng)建方式,Java內(nèi)部將此語句轉(zhuǎn)化為以下幾個步驟:

 (1)先定義一個名為str的對String類的對象引用變量:Stringstr;
 (2)在棧中查找有沒有存放值為“abc”的地址,如果沒有,則開辟一個存放字面值為“abc”的地址,接著創(chuàng)建一個新的String類的對象o,并將o的字符串值指向這個地址,而且在棧中這個地址旁邊記下這個引用的對象o。如果已經(jīng)有了值為“abc”的地址,則查找對象o,并返回o的地址。

 (3)將str指向?qū)ο髈的地址。

值得注意的是,一般String類中字符串值都是直接存值的。但像Stringstr="abc";這種場合下,其字符串值卻是保存了一個指向存在棧中數(shù)據(jù)的引用。
為了更好地說明這個問題,我們可以通過以下的幾個代碼進(jìn)行驗(yàn)證。

Java代碼

  1. Stringstr1=“abc”;  
  2. Stringstr2=“abc”;  
  3. System.out.println(s1==s2);//true  
  4.  
  5. Stringstr1=“abc”;  
  6. Stringstr2=“abc”;  
  7. System.out.println(s1==s2);//true  
  8.  

注意,這里并不用str1.equals(str2);的方式,因?yàn)檫@將比較兩個字符串的值是否相等。==號,根據(jù)JDK的說明,只有在兩個引用都指向了同一個對象時(shí)才返回真值。而我們在這里要看的是,str1與str2是否都指向了同一個對象。

  我們再接著看以下的代碼。

Java代碼 

  1. Stringstr1=newString(“abc”);  
  2. Stringstr2=“abc”;  
  3. System.out.println(str1==str2);//false  
  4.  
  5. Stringstr1=newString(“abc”);  
  6. Stringstr2=“abc”;  
  7. System.out.println(str1==str2);//false   

創(chuàng)建了兩個引用。創(chuàng)建了兩個對象。兩個引用分別指向不同的兩個對象。
  以上兩段代碼說明,只要是用new()來新建對象的,都會在堆中創(chuàng)建,而且其字符串是單獨(dú)存值的,即使與棧中的數(shù)據(jù)相同,也不會與棧中的數(shù)據(jù)共享。

f)數(shù)組

當(dāng)定義一個數(shù)組,intx[];或int[]x;時(shí),在棧內(nèi)存中創(chuàng)建一個數(shù)組引用,通過該引用(即數(shù)組名)來引用數(shù)組。x=newint[3];將在堆內(nèi)存中分配3個保存int型數(shù)據(jù)的空間,堆內(nèi)存的首地址放到棧內(nèi)存中,每個數(shù)組元素被初始化為0。

g)靜態(tài)變量

用static的修飾的變量和方法,實(shí)際上是指定了這些變量和方法在內(nèi)存中的“固定位置”-staticstorage,可以理解為所有實(shí)例對象共有的內(nèi)存空間。static變量有點(diǎn)類似于C中的全局變量的概念;靜態(tài)表示的是內(nèi)存的共享,就是它的每一個實(shí)例都指向同一個內(nèi)存地址。把static拿來,就是告訴JVM它是靜態(tài)的,它的引用(含間接引用)都是指向同一個位置,在那個地方,你把它改了,它就不會變成原樣,你把它清理了,它就不會回來了。

那靜態(tài)變量與方法是在什么時(shí)候初始化的呢?對于兩種不同的類屬性,static屬性與instance屬性,初始化的時(shí)機(jī)是不同的。instance屬性在創(chuàng)建實(shí)例的時(shí)候初始化,static屬性在類加載,也就是第一次用到這個類的時(shí)候初始化,對于后來的實(shí)例的創(chuàng)建,不再次進(jìn)行初始化。
我們??煽吹筋愃埔韵碌睦觼碚f明這個問題:

Java代碼 

  1. classStudent{  
  2. staticintnumberOfStudents=0;  
  3. Student()  
  4. {  
  5. numberOfStudents++;  
  6. }  
  7. }  
  8.  
  9. classStudent{  
  10. staticintnumberOfStudents=0;  
  11. Student()  
  12. {  
  13. numberOfStudents++;  
  14. }  
  15. }  

每一次創(chuàng)建一個新的Student實(shí)例時(shí),成員numberOfStudents都會不斷的遞增,并且所有的Student實(shí)例都訪問同一個numberOfStudents變量,實(shí)際上intnumberOfStudents變量在內(nèi)存中只存儲在一個位置上。

【編輯推薦】

  1. 遠(yuǎn)離陋習(xí) Java內(nèi)存管理的9個小技巧
  2. Java內(nèi)存管理的幾個技巧
  3. JVM.dll裝載過程與源代碼分析
  4. 巧解使Eclipse崩潰的JVM terminated問題
  5. 解決JVM Terminated.ExitCode=-1問題行之有效的方法

 

責(zé)任編輯:佚名 來源: javaeye.com
相關(guān)推薦

2010-07-07 09:02:30

SQL Server內(nèi)

2014-11-10 09:51:18

數(shù)據(jù)中心ITIL

2023-07-25 15:06:39

2015-06-04 10:19:33

數(shù)據(jù)中心

2023-11-02 00:18:47

風(fēng)險(xiǎn)管理系統(tǒng)驅(qū)動

2009-10-21 14:48:39

Oracle用戶權(quán)限表

2010-05-27 09:17:44

Linux網(wǎng)絡(luò)流量

2011-03-03 10:32:28

ProftpdMysql管理

2023-08-31 00:02:28

2010-06-02 18:09:30

SVN建立本地文件

2009-12-08 17:26:47

博科資訊零基預(yù)算管理

2011-04-26 14:13:59

扁平化扁平化網(wǎng)絡(luò)

2023-10-30 00:06:22

2021-10-18 10:43:59

數(shù)據(jù)數(shù)據(jù)中心DCIM

2012-02-06 09:40:25

2012-04-20 09:35:53

大數(shù)據(jù)數(shù)據(jù)中心數(shù)據(jù)質(zhì)量管理

2010-08-06 09:39:53

Linux流量控制

2012-11-22 14:59:50

2018-01-23 07:15:42

2013-10-09 09:32:56

BYOD策略BYOD
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號