经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C++ » 查看文章
C++在HotSpot VM中一种巧妙的内存管理方式
来源:cnblogs  作者:鸠摩(马智)  时间:2023/10/9 9:22:18  对本文有异议

在HotSpot VM中定义了一个Relocation类及相关的子类,可以通过这些类操作不同的重定位数据,如在CodeCache中读写这些数据。这些类需要的内存很小,但是不同的类需要的内存大小又不一样,所以做了如下的设计:

  1. #include <cstdlib>
  2. #include "iostream"
  3.  
  4. class Relocation;
  5.  
  6. class RelocationHolder {
  7. friend class Relocation;
  8. private :
  9. enum {
  10. _relocbuf_size = 5
  11. };
  12. // 总共分配了5 * 8 = 40 字节大
  13. // 小的内存用来存储Relocation
  14. void* _relocbuf[ _relocbuf_size ];
  15. public :
  16. Relocation* reloc() const {
  17. return (Relocation*) &_relocbuf[0];
  18. }
  19. };
  20.  
  21.  
  22. class Relocation {
  23. public:
  24. void *operator new(size_t size, const RelocationHolder &holder) {
  25. // 由于Relocation是RelocationHolder的友元,
  26. // 所以能访问其私有的_relocbuf数据
  27. if (size > sizeof(holder._relocbuf)) {
  28. std::cerr << "error" << std::endl;
  29. }
  30. return holder.reloc();
  31. }
  32. // 虚函数,子类可重写,这样能进行动态分派
  33. virtual void pack_data_to() {}
  34. };
  35.  
  36. class DataRelocation : public Relocation {
  37. private:
  38. int _data; // 具体数据
  39. public:
  40. DataRelocation(int data){
  41. _data = data;
  42. }
  43.  
  44. virtual void pack_data_to() {
  45. std::cout << "DataReloction::pack_data_to()" << std::endl;
  46. }
  47. };
  48.  
  49. class CallRelocation : public Relocation {
  50. private:
  51. u_char* _call_pc; // 具体数据
  52. public:
  53. CallRelocation(u_char* call_pc) {
  54. _call_pc = call_pc;
  55. }
  56.  
  57. virtual void pack_data_to() {
  58. std::cout << "CallRelocation::pack_data_to()" << std::endl;
  59. }
  60. };

其中的RelocationHolder是一个具体的Relocation的持有者。DataRelocation和CallRelocation代表了不同的重定位数据,可以调用对应的pack_data_to()函数按一定的规则将相应的数据写入CodeCache中。

下面看具体的使用,如下:

  1. int main() {
  2. // 在栈上分配内存
  3. RelocationHolder rh;
  4.  
  5. // 使用RelocationHolder中的_relocbuf数组占用的内存为DataRelocation
  6. // 分配内存
  7. u_char *addr = NULL;
  8. CallRelocation *dr = new(rh) CallRelocation(addr);
  9. dr->pack_data_to();
  10.  
  11. // DataRelocation操作完成后,重用RelocationHolder中_relocbuf的
  12. // 内存
  13. DataRelocation *cr = new(rh) DataRelocation(100);
  14. cr->pack_data_to();
  15.  
  16. return 0;
  17. }

RelocationHolder中的_relocbuf数组有固定的40字节内存,这些内存都分配在栈上,而DataRelocation或CallRelocation虽然需要的内存大小不同,但是都小于40字节,所以当CallRelocation使用完后,DataRelocation又可以重用这一部分栈内存。虽然使用new关键字创建了2个对象,但是分配的内存都在栈上,不需要释放。当函数返回时,对象会自动失效。

运行后的结果如下:

  1. DataReloction::pack_data_to()
  2. CallRelocation::pack_data_to()

如上的方法已经能满足一部分需求,但是使用起来不方便,首先需要找一个RelocationHolder,然后还需要自己创建一个对应的Relocation实例出来。为了让程序用起来更方便,也更优雅一些,HotSpot VM又增加了一些设计,提供了工厂方法,改造后的代码如下:

  1. class Relocation {
  2. public:
  3. static RelocationHolder newHolder() {
  4. // 调用默认的构造函数,生成一个在栈上分配内存的
  5. // RelocationHolder类型的对象
  6. // 注意,这里创建的对象在调用完函数后会
  7. // 失效,返回的是一个通过拷贝构造函数
  8. // 拷贝到栈上的一个临时对象
  9. return RelocationHolder();
  10. }
  11.  
  12. void *operator new(size_t size, const RelocationHolder &holder) {
  13. // 由于Relocation是RelocationHolder的友元,
  14. // 所以能访问其私有的_relocbuf数据
  15. if (size > sizeof(holder._relocbuf)) {
  16. std::cerr << "error" << std::endl;
  17. }
  18. return holder.reloc();
  19. }
  20.  
  21. virtual void pack_data_to() {}
  22. };
  23.  
  24. class DataRelocation : public Relocation {
  25. private:
  26. int _data;
  27. public:
  28. DataRelocation(int data){
  29. _data = data;
  30. }
  31. static RelocationHolder spec(int data) {
  32. RelocationHolder rh = newHolder();
  33. new(rh) DataRelocation(data);
  34. return rh;
  35. }
  36.  
  37. virtual void pack_data_to() {
  38. std::cout << "DataReloction::pack_data_to()" << std::endl;
  39. }
  40. };
  41.  
  42. class CallRelocation : public Relocation {
  43. private:
  44. u_char* _call_pc;
  45. public:
  46. CallRelocation(u_char* call_pc) {
  47. _call_pc = call_pc;
  48. }
  49. static RelocationHolder spec(u_char* call_pc) {
  50. RelocationHolder rh = newHolder();
  51. new(rh) CallRelocation(call_pc);
  52. return rh;
  53. }
  54.  
  55. virtual void pack_data_to() {
  56. std::cout << "CallRelocation::pack_data_to()" << std::endl;
  57. }
  58. };

RelocationHolder类不需要改动,主要是为CallRelocation和DataRelocation增加了工厂方法spec(),同样使用的是栈上分配的内存,不需要释放,使用时只需要这样:

  1. void relocate(RelocationHolder const& spec) {
  2. Relocation* reloc = spec.reloc();
  3. // 处理重定位相关数据
  4. reloc->pack_data_to();
  5. };
  6.  
  7.  
  8. int main() {
  9. // 收集重定位相关数据
  10. u_char *addr = NULL;
  11. RelocationHolder r1 = CallRelocation::spec(addr);
  12. relocate(r1);
  13.  
  14. RelocationHolder r2 = DataRelocation::spec(100);
  15. relocate(r2);
  16.  
  17. return 0;
  18. }

这样看起来是不是要比之前更加简洁了呢?在一个函数中收集数据,在另外的函数中处理数据。  

本人最近准备出一个手写Hotspot VM的课程,超级硬核,从0开始写HotSpot VM,将HotSpot VM所有核心的实现全部走一遍,如感兴趣,加我速速入群。

已加群的不要重复加。

群里可讨论虚拟机和Java性能剖析与故障诊断等话题,欢迎加入。

 

 

 

 

 

 

 

  

 

原文链接:https://www.cnblogs.com/mazhimazhi/p/17742626.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号