织梦大气绿色大气农业能源化工机械产品企业网站源码模版,建筑工程知识零基础,鲜花网网站开发的意义,上海做门户网站的公司RAII#xff08;Resource Acquisition Is Initialization#xff09;#xff0c;也称为“资源获取就是初始化”#xff0c;是C语言的一种管理资源、避免泄漏的惯用法。C标准保证任何情况下#xff0c;已构造的对象最终会销毁#xff0c;即它的析构函数最终会被调用。简单…RAIIResource Acquisition Is Initialization也称为“资源获取就是初始化”是C语言的一种管理资源、避免泄漏的惯用法。C标准保证任何情况下已构造的对象最终会销毁即它的析构函数最终会被调用。简单的说RAII的做法是使用一个对象在其构造时获取资源在对象生命期控制范围之下对资源的访问始终保持有效最后在对象析构的时候释放资源。 在HotSpot VM中RAII对内存资源的管理和释放、明确定义范围锁及记录重要信息等方面起到了非常重要的作用。下面详细介绍一下。
1、定义范围锁
在HotSpot VM中整个系统正确的运转需要非常多的锁这些锁很多都是通过RAII技术来管理的。 举个例子如下
class MutexLocker {
private:pthread_mutex_t *_mtx;
public:MutexLocker(pthread_mutex_t *mtx) {if (mtx) {_mtx mtx;pthread_mutex_lock(_mtx);}}~MutexLocker() {if (_mtx)pthread_mutex_unlock(_mtx);}
};在类的构造和析构函数中对互斥量进行加载和释放锁。也就是说当对象创建的时候会自动调用构造函数当对象超出作用域的时候会自动调用析构函数。
现在我们通过如上的类将一段代码保护起来防止产生并发问题
// 初始化互斥锁
pthread_mutex_t mutex PTHREAD_MUTEX_INITIALIZER;void init(){MutexLocker locker(mutex);// 整个方法都会在同步锁的保护下执行
}我们还可以通过匿名块来进一步细化锁控制的范围。当进入作用域范围时C会自动调用MutexLocker的构造函数当出了作用域范围时会调用MutexLocker析构函数。这样通过类来管理锁资源将资源和对象的生命周期绑定。在Java中有个类似的、饱受诟病的一种释放资源的办法重写finalize()方法由于开发人员无法对Java对象的生命周期进行精确控制而是托管给了Java虚拟机GC所以对象什么时候回收是一个未知数为应用程序埋下了一个定时炸弹。不过另外一个类似的语法try-with-resources提倡使用。 在HotSpot VM中在runtime/mutex.hpp文件中定义了互斥量Mutex这个互斥量继承自MonitorHotSpot VM内部的并发非常依赖Monitor。在runtime/mutexLocker.hpp文件中定义了MutexLocker、MutexLockerEx等类来控制锁范围。
2、管理内存资源
管理内存资源的一些类有HandleMark、ResourceMark等HandleMark用来管理句柄ResourceMark用来管理临时使用的内存。 HandleMark我在之前已经介绍的非常详细了可参考如下文章 第2.7篇-操作句柄Handle 第2.8篇-句柄Handle的释放 ResourceMark的实现也非常类似。 由于Java类常量池中的字符串、还有一些公共字符串在HotSpot VM中都用Symbol实例来表示如果想要看某个Klass实例表示的具体的类名称我有时候会这样做
{ResourceMark rm;Symbol *sym _klass-name();const char *klassName (sym-as_C_string());// ...
}调用的as_C_string()函数实现如下
char* Symbol::as_C_string() const {int len utf8_length();char* str (char*) resource_allocate_bytes( (len 1) * sizeof(char) );return as_C_string(str, len 1);
}extern char* resource_allocate_bytes(size_t size, AllocFailType alloc_failmode) {ResourceArea* ra Thread::current()-resource_area();return ra-allocate_bytes(size, alloc_failmode);
}可以看到从ResourceArea中申请了内存那就必须要记录完成调用之后恢复调用之前的样子这样才不会让内存处在不一致的状态从而导致崩溃所以必须要使用ResourceMark。
3、保存重要信息
阅读HotSpot VM源代码的人一定会对JavaCalls::call_helper()函数中的如下这段代码不陌生 从HotSpot VM内部调用Java方法时通常会调用到call_helper()函数所以这也是HotSpot VM调用Java主类main()方法的关键入口在这个函数中我们能够看到HandleMark的使用另外还有一个JavaCallWrapper这个类主要有2个作用 1管理内存资源在 第42篇-JNI引用的管理1 已经详细介绍过这里不再介绍。 2记录Java调用栈的重要信息退栈等操作非常依赖这些信息。 变量名叫link非常贴切它的起用就是将Java栈连接起来其大概的实现过程如下图所示。
后面我们在介绍具体的知识点时再详细介绍这些内容。
RAII技术被认为是C中管理资源的最佳方法进一步引申使用RAII技术也可以实现安全、简洁的状态管理编写出优雅的异常安全的代码。它利用栈对象在离开作用域后自动析构的语言特点将受限资源的生命周期绑定到该对象上当对象析构时以达到自动释放资源的目的。
简单而言RAII就是指资源在我们拿到时就已经初始化一旦不在需要该资源就可以自动释放该资源。
本人最近准备出一个手写Hotspot VM的课程超级硬核从0开始写HotSpot VM将HotSpot VM所有核心的实现全部走一遍如感兴趣速速入群。
群里可讨论虚拟机和Java性能剖析与故障诊断等话题欢迎加入。