让HotSpot生成固定的ReservedSpace地址可以更简单方便的调试汇编代码
ZHH2009
2014-07-30
HotSpot初始化阶段在src\share\vm\runtime\virtualspace.cpp的如下代码中生成ReservedSpace
ReservedSpace::ReservedSpace(size_t size, size_t alignment, bool large, bool executable) { initialize(size, alignment, large, NULL, 0, executable); } 这种方式生成的地址是随机的,导致加上如下三个参数时 +PrintStubCode +PrintAssembly +PrintInterpreter 生成的汇编代码的地址也是随机的,不方便调试, 后来发现只要把前面的代码改成如下: ReservedSpace::ReservedSpace(size_t size, size_t alignment, bool large, bool executable) { //0x01cd0000是requested_address initialize(size, alignment, large, (char *)0x01cd0000, 0, executable); } 这样生成的汇编代码的地址每次都一样了, 比如StubRoutines::call_stub的汇编代码固定如下: //... ;; loop: 0x01cd0425: mov -0x4(%edx,%ecx,4),%eax 0x01cd0429: mov %eax,(%esp,%ebx,4) 0x01cd042c: inc %ebx 0x01cd042d: dec %ecx 0x01cd042e: jne 0x01cd0425 ;; parameters_done: 0x01cd0430: mov 0x14(%ebp),%ebx 0x01cd0433: mov 0x18(%ebp),%eax 0x01cd0436: mov %esp,%esi ;; call Java function 0x01cd0438: call *%eax //... ;; call_stub_return_address: 调试时,只要按地址打断点就能精确地到达你想要的那条汇编, 比如0x01cd0438对应的肯定是call *%eax,从这里转到method entry point的汇编。 只不过有一点点缺陷,我用的是windows, 发现没有正确释放requested_address 对应的空间, 导致不是每次重启HotSpot时都成功,多试几次又好了。 requested_address从0x01cd0000换成0x7f00000成功次要多一些 我甚至在ReservedSpace::initialize中加了如下代码: void initialize(size_t size, size_t alignment, bool large, char* requested_address, const size_t noaccess_prefix, bool executable) { //... if (requested_address != 0) { unsigned int count = 10; while(count) { base = os::attempt_reserve_memory_at(size, requested_address); if (failed_to_reserve_as_requested(base, requested_address, size, false)) { // OS ignored requested address. Try different address. base = NULL; os::release_memory(requested_address, size); count--; } else { break; } } } else { base = os::reserve_memory(size, NULL, alignment); } //... } |
|
nijiaben
2014-07-30
不知道windows下是不是不一样,我在linux下没这个问题,产生的base地址都是一样的,还有你这么设置写死的话,这个构造函数被调用多次,也就第一次调用的时候能分配到那个地址吧
PS:我倒是觉得线程在刚start的时候会在栈空间上会随机分配一段内存,要想精准调试这个倒是可以控制一下,我的做法是将那随机分配的代码注释了 |
|
ZHH2009
2014-07-30
那个构造函数只调用一次,其他gc相关的不用这个构造函数,
如果不写死得到的各个stub的地址就不同了。 stub跟线程不相关吧,毕竟在生成stub时,都还没有java线程. |
|
nijiaben
2014-07-30
恩,只有CodeCache会调用一下
我之前也碰到过类似的问题,也是希望调试汇编的时候,希望每次都能地址一致,我微薄之前有提到 http://weibo.com/p/1005051071312434/weibo?profile_ftype=1&key_word=randomize_va_space&is_search=1#_0 |
|
ZHH2009
2014-07-30
我没试过你的方法,因为我是用windows,不是用linux。
在linux下把内核参数randomize_va_space设为0对此贴中提到的问题有帮助吗? 有帮助的话,当然是只调内核参数好。 |
|
rink1969
2014-07-30
ZHH2009 写道 只不过有一点点缺陷,我用的是windows, 发现没有正确释放requested_address 对应的空间, 导致不是每次重启HotSpot时都成功,多试几次又好了。 这个应该不是没释放的问题 而是这段地址空间被动态库或者其他东西占用了。 可以在链接脚本里面把这段地址空间预留出来,就不会有这样的问题了。 |
|
nijiaben
2014-07-30
ZHH2009 写道 我没试过你的方法,因为我是用windows,不是用linux。
在linux下把内核参数randomize_va_space设为0对此贴中提到的问题有帮助吗? 有帮助的话,当然是只调内核参数好。 我在linux下没碰到你说的问题,返回的base地址都是一样的,那个内核参数没设置,我那么做当初主要是了解线程栈结构的时候做的,当时碰到的问题是帧结构里的数据的位置是变化的,最终发现原来在线程启动的时候在栈上随机取了一段,导致每次重启相同线程的相同帧的内存地址是不一样的 |
|
nijiaben
2014-07-30
rink1969 写道 ZHH2009 写道 只不过有一点点缺陷,我用的是windows, 发现没有正确释放requested_address 对应的空间, 导致不是每次重启HotSpot时都成功,多试几次又好了。 这个应该不是没释放的问题 而是这段地址空间被动态库或者其他东西占用了。 可以在链接脚本里面把这段地址空间预留出来,就不会有这样的问题了。 每个进程都是一套全新的完整的虚拟空间地址,应该不会因为没释放的问题,rink1969说的可能是原因,可以看看没有分配到你想要的地址的时候,预期的地址被哪个动态库占了 |
|
ZHH2009
2014-07-30
nijiaben 写道 rink1969 写道 ZHH2009 写道 只不过有一点点缺陷,我用的是windows, 发现没有正确释放requested_address 对应的空间, 导致不是每次重启HotSpot时都成功,多试几次又好了。 这个应该不是没释放的问题 而是这段地址空间被动态库或者其他东西占用了。 可以在链接脚本里面把这段地址空间预留出来,就不会有这样的问题了。 每个进程都是一套全新的完整的虚拟空间地址,应该不会因为没释放的问题,rink1969说的可能是原因,可以看看没有分配到你想要的地址的时候,预期的地址被哪个动态库占了 HotSpot本身就是一个DLL,如果第一次运行HotSpot成功了,第二次通常都失败,然后稍等片刻,运行第3或第4次又好了,在此期间并没有运行其他任何程序。 windows下是通过(char*)VirtualAlloc(addr, bytes, MEM_RESERVE, PAGE_READWRITE)来进行的,失败时,这个API就返回NULL。 |
|
ZHH2009
2014-07-30
ZHH2009 写道 ZHH2009 写道 只不过有一点点缺陷,我用的是windows, 发现没有正确释放requested_address 对应的空间, 导致不是每次重启HotSpot时都成功,多试几次又好了。 HotSpot本身就是一个DLL,如果第一次运行HotSpot成功了,第二次通常都失败,然后稍等片刻,运行第3或第4次又好了,在此期间并没有运行其他任何程序。 windows下是通过(char*)VirtualAlloc(addr, bytes, MEM_RESERVE, PAGE_READWRITE)来进行的,失败时,这个API就返回NULL。 当为NULL时,我用GetLastError得到的错误是 487 ERROR_INVALID_ADDRESS |