鍍金池/ 教程/ Java/ Java 平臺與內(nèi)存管理
異常處理
基本類型與運算
Java 平臺與內(nèi)存管理
XML
輸入輸出流
JDBC 與數(shù)據(jù)庫
字符串與數(shù)組
Java 多線程
面向?qū)ο缶幊?/span>
集合類
UML
J2EE 與 EJB
Java 基本概念
Servlet 與 JSP
關(guān)鍵字
常見設(shè)計模式
SSH 架構(gòu)

Java 平臺與內(nèi)存管理

1. GC線程是否為守護線程?()

答案:是

解析:線程分為守護線程和非守護線程(即用戶線程)。

只要當(dāng)前JVM實例中尚存在任何一個非守護線程沒有結(jié)束,守護線程就全部工作;只有當(dāng)最后一個非守護線程結(jié)束時,守護線程隨著 JVM 一同結(jié)束工作。 守護線程最典型的應(yīng)用就是 GC (垃圾回收器)

2. 解釋內(nèi)存中的棧(stack)、堆(heap)和靜態(tài)存儲區(qū)的用法。

答:通常我們定義一個基本數(shù)據(jù)類型的變量,一個對象的引用,還有就是函數(shù)調(diào)用的現(xiàn)場保存都使用內(nèi)存中的??臻g;而通過new關(guān)鍵字和構(gòu)造器創(chuàng)建的對象放在堆空間;程序中的字面量(literal)如直接書寫的100、“hello”和常量都是放在靜態(tài)存儲區(qū)中。棧空間操作最快但是也很小,通常大量的對象都是放在堆空間,整個內(nèi)存包括硬盤上的虛擬內(nèi)存都可以被當(dāng)成堆空間來使用。

String str = new String(“hello”);

上面的語句中 str 放在棧上,用 new 創(chuàng)建出來的字符串對象放在堆上,而“hello”這個字面量放在靜態(tài)存儲區(qū)。

3. Java 中會存在內(nèi)存泄漏嗎,請簡單描述。

答:理論上 Java 因為有垃圾回收機制(GC)不會存在內(nèi)存泄露問題(這也是 Java 被廣泛使用于服務(wù)器端編程的一個重要原因);然而在實際開發(fā)中,可能會存在無用但可達的對象,這些對象不能被 GC 回收也會發(fā)生內(nèi)存泄露。一個例子就是 Hibernate 的Session(一級緩存)中的對象屬于持久態(tài),垃圾回收器是不會回收這些對象的,然而這些對象中可能存在無用的垃圾對象。下面的例子也展示了 Java 中發(fā)生內(nèi)存泄露的情況:

package com.lovo;  

import java.util.Arrays;  
import java.util.EmptyStackException;  

public class MyStack<T> {  
    private T[] elements;  
    private int size = 0;  

    private static final int INIT_CAPACITY = 16;  

    public MyStack() {  
        elements = (T[]) new Object[INIT_CAPACITY];  
    }  

    public void push(T elem) {  
        ensureCapacity();  
        elements[size++] = elem;  
    }  

    public T pop() {  
        if(size == 0)   
            throw new EmptyStackException();  
        return elements[--size];  
    }  

    private void ensureCapacity() {  
        if(elements.length == size) {  
            elements = Arrays.copyOf(elements, 2 * size + 1);  
        }  
    }  
}  

上面的代碼實現(xiàn)了一個棧(先進后出(FILO))結(jié)構(gòu),乍看之下似乎沒有什么明顯的問題,它甚至可以通過你編寫的各種單元測試。然而其中的 pop 卻存在內(nèi)存泄露的問題,當(dāng)我們用 pop 方法彈出棧中的對象時,該對象不會被當(dāng)作垃圾回收,即使使用棧的程序不再引用這些對象,因為棧內(nèi)部維護著對這些對象的過期引用(obsolete reference)。在支持垃圾回收的語言中,內(nèi)存泄露是很隱蔽的,這種內(nèi)存泄露其實就是無意識的對象保持。如果一個對象引用被無意識的保留起來了,那么垃圾回收器不會處理這個對象,也不會處理該對象引用的其他對象,即使這樣的對象只有少數(shù)幾個,也可能會導(dǎo)致很多的對象被排除在垃圾回收之外,從而對性能造成重大影響,極端情況下會引發(fā) Disk Paging(物理內(nèi)存與硬盤的虛擬內(nèi)存交換數(shù)據(jù)),甚至造成 OutOfMemoryError。

4. GC 是什么?為什么要有 GC?

答:GC 是垃圾收集的意思,內(nèi)存處理是編程人員容易出現(xiàn)問題的地方,忘記或者錯誤的內(nèi)存回收會導(dǎo)致程序或系統(tǒng)的不穩(wěn)定甚至崩潰,Java 提供的 GC 功能可以自動監(jiān)測對象是否超過作用域從而達到自動回收內(nèi)存的目的,Java 語言沒有提供釋放已分配內(nèi)存的顯示操作方法。Java 程序員不用擔(dān)心內(nèi)存管理,因為垃圾收集器會自動進行管理。要請求垃圾收集,可以調(diào)用下面的方法之一:System.gc()Runtime.getRuntime().gc() ,但 JVM 可以屏蔽掉顯示的垃圾回收調(diào)用。

垃圾回收可以有效的防止內(nèi)存泄露,有效的使用可以使用的內(nèi)存。垃圾回收器通常是作為一個單獨的低優(yōu)先級的線程運行,不可預(yù)知的情況下對內(nèi)存堆中已經(jīng)死亡的或者長時間沒有使用的對象進行清除和回收,程序員不能實時的調(diào)用垃圾回收器對某個對象或所有對象進行垃圾回收。在 Java 誕生初期,垃圾回收是 Java 最大的亮點之一,因為服務(wù)器端的編程需要有效的防止內(nèi)存泄露問題,然而時過境遷,如今 Java 的垃圾回收機制已經(jīng)成為被詬病的東西。移動智能終端用戶通常覺得 iOS 的系統(tǒng)比 Android 系統(tǒng)有更好的用戶體驗,其中一個深層次的原因就在于 Android 系統(tǒng)中垃圾回收的不可預(yù)知性。

5. 第 3 行中生成的 object在第幾行執(zhí)行后成為 garbage collection 的對象?

1.public class MyClass {

2. public StringBuffer aMethod() {

3. StringBuffer sf = new StringBuffer(“Hello”);

4. StringBuffer[] sf_arr = new StringBuffer[1];

5. sf_arr[0] = sf;

6. sf = null;

7. sf_arr[0] = null;

8. return sf;

9. }

10.}

答:第 7 行

6. 描述一下 JVM 加載 class 文件的原理機制?

答:JVM 中類的裝載是由類加載器(ClassLoader) 和它的子類來實現(xiàn)的,Java 中的類加載器是一個重要的 Java 運行時系統(tǒng)組件,它負責(zé)在運行時查找和裝入類文件中的類。

  1. 由于 Java 的跨平臺性,經(jīng)過編譯的 Java 源程序并不是一個可執(zhí)行程序,而是一個或多個類文件。當(dāng) Java 程序需要使用某個類時,JVM 會確保這個類已經(jīng)被加載、連接(驗證、準備和解析)和初始化。類的加載是指把類的 .class 文件中的數(shù)據(jù)讀入到內(nèi)存中,通常是創(chuàng)建一個字節(jié)數(shù)組讀入 .class 文件,然后產(chǎn)生與所加載類對應(yīng)的 Class 對象。加載完成后,Class 對象還不完整,所以此時的類還不可用。當(dāng)類被加載后就進入連接階段,這一階段包括驗證、準備(為靜態(tài)變量分配內(nèi)存并設(shè)置默認的初始值)和解析(將符號引用替換為直接引用)三個步驟。最后 JVM 對類進行初始化,包括:1. 如果類存在直接的父類并且這個類還沒有被初始化,那么就先初始化父類;2. 如果類中存在初始化語句,就依次執(zhí)行這些初始化語句。

  2. 類的加載是由類加載器完成的,類加載器包括:根加載器(BootStrap)、擴展加載器(Extension)、系統(tǒng)加載器(System)和用戶自定義類加載器(java.lang.ClassLoader的子類)。從JDK 1.2開始,類加載過程采取了父親委托機制(PDM)。PDM 更好的保證了 Java 平臺的安全性,在該機制中,JVM 自帶的 Bootstrap 是根加載器,其他的加載器都有且僅有一個父類加載器。類的加載首先請求父類加載器加載,父類加載器無能為力時才由其子類加載器自行加載。JVM 不會向 Java 程序提供對 Bootstrap 的引用。下面是關(guān)于幾個類加載器的說明:

a)Bootstrap:一般用本地代碼實現(xiàn),負責(zé)加載JVM基礎(chǔ)核心類庫(rt.jar);

b)Extension:從 java.ext.dirs 系統(tǒng)屬性所指定的目錄中加載類庫,它的父加載器是 Bootstrap;

c)System:又叫應(yīng)用類加載器,其父類是Extension。它是應(yīng)用最廣泛的類加載器。它從環(huán)境變量 classpath 或者系統(tǒng)屬性 java.class.path 所指定的目錄中記載類,是用戶自定義加載器的默認父加載器。

上一篇:SSH 架構(gòu)