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的内容暂时就记到这里了,代码地址在: 这里。  

发布了340 篇原创文章 · 获赞 159 · 访问量 13万+

猜你喜欢

转载自blog.csdn.net/qq_36285943/article/details/104733541