复制(分代)垃圾收集提供了任何形式的自动内存管理的最佳性能,但需要修复重定位数据块的指针。通过禁用指针算法并确保所有指针都指向可识别对象的开头,可以在支持此内存管理技术的语言中启用此功能。
如果你在运行时使用JIT编译器生成代码,事情看起来有点棘手,因为调用堆栈上的返回地址将指向,而不是代码块的开头,而是指向其中的随机位置,因此fixup是一个问题
这通常如何解决?
答案 0 :(得分:1)
通常,您不重新定位代码。这是因为修复堆栈和其他地址确实很复杂(想想跳过代码片段),并且因为你实际上并不需要为这样的代码进行垃圾收集(因为它只是由你编写的代码操纵,所以你可以做手动内存管理)。您也不希望创建大量的机器代码(与应用程序对象相比),因此碎片等不是问题。
如果你坚持移动机器代码并修复堆栈,那么是的一种方式,我认为:与Mark-Compact类似,构建一个“休息表”(我不知道这是哪里名称来自;“重定位表”可能更清晰),它告诉您应该调整指向移动对象的指针的数量。现在,遍历堆栈以获取返回地址(当然是高度特定于平台的)并在它们引用重定位代码时修复它们。而不是查找完全匹配,而是搜索低于您当前正在替换的返回地址的最高地址。你可以通过查看对象大小来检查这个地址是否确实引用了一些机器代码(毕竟你有一个指向对象开头的指针)。由于各种原因,这种方法对所有对象都不可行。
还有其他原因可以做类似的事情。一些JIT编译器具有堆栈替换,这意味着创建一些机器代码的新版本(例如,更优化或更少优化)并用它替换旧版本的所有实例。这比修复返回地址要复杂得多。您必须确保新版本在逻辑上继续保留旧版本。我不熟悉这是如何实现的,所以我不会详细介绍。