windows系統使用c++實現一個小型jvm(四)------------jvm的gc 以及 jvm是什麼

  這篇文章記錄一下gc和對虛擬機的理解,其它的相關jvm的內容就暫時先不涉及了,以後有機會再弄。 

1.gc流程

     在前臺的文章中,我記錄了一個模擬的gc流程,那個裏面由於對於根對象 具有很高的抽象程度,因此對java的gc想要去了解一下,這裏分塊看看gc的源碼:

// 0. create a TEMP new-oop-pool:
    unordered_map<Oop *, Oop *> new_oop_map;		// must be `map/set` instead of list, for getting rid of duplication!!!

    首先,定義一個緩存容器。 

 Oop *new_oop;		// global local variable

    // 0.5. first migrate all of the basic type mirrors.
    for (auto & iter : java_lang_class::get_single_basic_type_mirrors()) {
        Oop *mirror = iter.second;
        recursive_add_oop_and_its_inner_oops_and_modify_pointers_by_the_way(mirror, new_oop_map);
        iter.second = (MirrorOop *)mirror;
    }
    // 0.7. I don't want to uninstall all StringTable...
    unordered_set<Oop *, java_string_hash, java_string_equal_to> new_string_table;
    for (auto & iter : java_lang_string::get_string_table()) {
        new_oop = iter;
        recursive_add_oop_and_its_inner_oops_and_modify_pointers_by_the_way(new_oop, new_oop_map);
        new_string_table.insert(new_oop);
    }
    new_string_table.swap(java_lang_string::get_string_table());

  然後收集全局變量。 

 // 1. for all GC-Roots [InstanceKlass]:
    for (auto iter : system_classmap) {
        klass_inner_oop_gc(iter.second, new_oop_map);		// gc the klass
    }
    for (auto iter : AutomanClassLoader::get_loader().classmap) {
        klass_inner_oop_gc(iter.second, new_oop_map);		// gc the klass
    }
    for (auto iter : AutomanClassLoader::get_loader().anonymous_klassmap) {
        klass_inner_oop_gc(iter, new_oop_map);		// gc the klass
    }

    然會回收類實例(這個流程可能是 卸載,與加載類對應);

// 2. for all GC-Roots [vm_threads]:
    for (auto & thread : automan_jvm::threads()) {
//		std::wcout << "thread: " << thread.tid << ", has " << thread.vm_stack.size() << " frames... "<< std::endl;		// delete
        // 2.3. for thread.args
        for (auto & iter : thread.arg) {
//			std::wcout << "arg: " << iter << std::endl;			// delete
            recursive_add_oop_and_its_inner_oops_and_modify_pointers_by_the_way(iter, new_oop_map);
        }
        for (auto & frame : thread.vm_stack) {
            // 2.5. for vm_stack::StackFrame::LocalVariableTable
            for (auto & oop : frame.localVariableTable) {
//				std::wcout << "localVariableTable: " << oop;			// delete
                recursive_add_oop_and_its_inner_oops_and_modify_pointers_by_the_way(oop, new_oop_map);
//				std::wcout << " to " << oop;			// delete
            }
            // 2.7. for vm_stack::StackFrame::op_stack
            // stack can't use iter. so make it with another vector...
            list<Oop *> temp;
            while(!frame.op_stack.empty()) {
                Oop *oop = frame.op_stack.top();	frame.op_stack.pop();
                temp.push_front(oop);
            }
            for (auto & oop : temp) {
//				std::wcout << "op_stack: " << oop;		// delete
                recursive_add_oop_and_its_inner_oops_and_modify_pointers_by_the_way(oop, new_oop_map);
//				std::wcout << " to " << oop;		// delete
            }
            for (auto & oop : temp) {
                frame.op_stack.push(oop);
            }
        }

    }

  然會回收線程的資源,包括本地變量表,虛擬機棧,操作棧,等可回收資源。 

    // 2.5. for all GC-Roots: ThreadTable
    for (auto & iter : ThreadTable::get_thread_table()) {
//		std::wcout << "thread: from " << iter.second.second;
        Oop *thread = std::get<1>(iter.second);
        recursive_add_oop_and_its_inner_oops_and_modify_pointers_by_the_way(thread, new_oop_map);
        std::get<1>(iter.second) = (InstanceOop *)thread;
//		std::wcout << " to " << iter.second.second;
    }

     然後回收線程。

// 3. create a new oop table and exchange with the global Mempool
    list<Oop *> new_oop_handler_pool;
    for (auto & iter : new_oop_map) {
        new_oop_handler_pool.push_back(iter.second);
    }
    // delete all:
    for (auto iter : Mempool::oop_handler_pool()) {
        delete iter;
    }
    // swap.
    new_oop_handler_pool.swap(Mempool::oop_handler_pool());
    // 4. final: must do this.
    gc() = false;				// no need to lock.
    //todo: 這裏gc完成後,通知所有的線程(由 gc線程發出通知)
    signal_all_thread();
    std::wcout << "gc over!!" << std::endl;		// delete

  最後回收資源,並處罰線程通知。 

  從代碼看,貌似沒有用分代回收。 。  emmmm... ,但是至少知道所謂的根是怎麼來的了。 

2.jvm虛擬機是什麼?

   這個主要是我用於對這段時間調試的理解。 

   之前總是聽說,java是介於解釋型與編譯型語言之間,即中間字節碼的方式運行的,它較純編譯語言的速度有所下降。  從源碼來分析,它的速度到底有哪些影響呢? 

    實際上,這個jvm的主題部分就是一個  switch...case...  結構,  其中,ByteCodeEngine在目前功能不完善的情況下,這個控制結構的代碼長度爲 3000多行。   注意,這是一個方法哦!   比絕大多數類都要大了。 

    在看看  case中,用於判斷的是  十六進制的 操作數,  類似於  0x01,0x02... 0xff  這種,數字有個什麼好處??   它是天然的索引!!!   簡言之,這個switch...case...結構是一顆天然的  B樹索引,任意一個操作的檢索時間爲  O(1)的時間複雜度。  從這個層面講,它與原生的程序幾乎沒有區別。 

    那爲什麼說它的速度有一定影響呢?我覺得主要從以下幾個方面考慮:

        1.任意一個java程序,它要啓動前,必須啓動jvm,啓動jvm我們前面已經說了,它會經歷那樣那樣的步驟。  不算輕量級。

        2.啓動一個java程序之後,它的內部會至少開闢三個線程,這就涉及到線程調度,而且gc線程調用較爲頻繁,這是比較耗時的。 

        3.雖然執行流程跟原生的並沒有多大區別,但是虛擬機棧,本地變量表,全局常量表 等等都是通過代碼維護,而純編譯語言這些東西是由操作系統維護的,它是機器碼級別。  所以這裏速度會有一些差別。


  jvm的內容暫時就記到這裏了,代碼地址在: 這裏。  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章