建筑设计类英文的网站,网站怎样优化seo,化工集团网站建设 中企动力,公司门户app下载了解保护页#xff0c;先从几个问题开始吧
1、为什么线程栈有栈帧了#xff0c;还要有保护页#xff1f;
答#xff1a;在操作系统中内存可以看成是一个大数组#xff0c;这就有一个问题#xff0c;线程之间可能会互相踩了别人的内存空间#xff0c;所以栈空间也存在这…了解保护页先从几个问题开始吧
1、为什么线程栈有栈帧了还要有保护页
答在操作系统中内存可以看成是一个大数组这就有一个问题线程之间可能会互相踩了别人的内存空间所以栈空间也存在这个问题。为了防止栈溢出时破坏栈之外的数据结构语言运行时会保留最大栈上限limit所在的一片区域这就是保护页Guard Page,也可叫哨兵值Sentry。当函数返回时检查保护页的值如果被修改说明已到达最大栈上限此时就要输出错误并终止程序。
2、Java栈溢出后保护页的作用
答Java也有栈溢出发生时会抛出StackOverflowError输出调用栈和代码行数。这些过程都需要额外执行很多方法但是发生栈溢出就意味着不能继续执行方法了因为方法执行需要栈空间。为了解决这个问题HotSpot虚拟机在C语言运行时提供的保护页Linux的JavaThread没有之外会使用create_stack_guard_pages()创建额外的保护页来支持栈溢出错误处理如图12-1所示。
3、保护页有几种类型及各类型的作用
答线程栈的最大上限处会保留三块保护页Guard Page支持栈溢出分别是Reserved Page、Yellow Page、Red Page。图12-1中的主要内容分析如下
1Reserved PageReserved Page旨在为一些关键段Critical Section方法保存外栈空间让有 jdk.internal.vm.annotation.ReservedStackAccess注解的方法能完成执行如lock与unlock之间的代码防止关键段方法中的对象出现不一致的状态。当执行关键段方法时分配的栈顶触及Reserved Page则虚拟机会将Reserved Page标记为正常栈空间供关键段方法完成执行然后再抛出StackOVerflowError。Reserved Page的大小由-XX:StackReservedPages指定。
2Yellow Page如果执行Java代码时分配的栈顶触及YellowPage则虚拟机会抛出StackOverflowError然后将Yellow Page标为正常栈空间让抛异常的代码有栈可用。Yellow Page的数量由参数-XX:StackYellowPages指定最后Yellow Page占用的空间是page数量*page大小page的大小一般是4KB如果开启-XX:UseLargePages且操作系统支持large page特性page的大小可达到4MB)。
3Red Page如果执行Java代码时分配的栈顶触及Red Page则虚拟机会创建错误日志hs_err_pid.log然后关闭虚拟机。同样为了让创建日志的代码执行虚拟机会将Red Page标为正常栈空间。RedPage的大小由-XX:StackRedPages指定。
4Shadow Page前面区域都是执行Java代码出现栈溢出的错误处理。虚拟机还可能执行native方法或者虚拟机本身需要执行的方法这些方法的栈大小不像Java代码一样能确定编译器能确定但是虚拟机不能如果开启虚拟机参数-XX:UseStackBangingJVM会分配一块足够大的Shadow Page执行如果RSP栈顶指针超出Shadow Page区则抛出StackOverflowError。
有了create_stack_guard_pages()创建的额外的保护页即便产生StackOverflowError虚拟机也能执行额外的代码正确地抛出Java异常并输出调用栈以提醒用户。
图12-1
图12-2 Java层面的栈布局
void JavaThread::create_stack_guard_pages() {if (!os::uses_stack_guard_pages() ||_stack_guard_state ! stack_guard_unused ||(DisablePrimordialThreadGuardPages os::is_primordial_thread())) {if (TraceThreadEvents) {tty-print_cr(Stack guard page creation for thread UINTX_FORMAT disabled, os::current_thread_id());}return;}// 这里为什么是栈基址减去栈大小呢因为在Linux系统中栈空间是从大到小开辟空间的栈顶(ESP) 栈基址EBP正常栈基址EBP应该是在上面而栈顶ESP是在下面所以图12-1和图12-2实际上把它们倒过来看就行画成正向的是为了从概念上和感观上看更清晰address low_addr stack_base() - stack_size();// 根据设置的Yellow Page数和Red Page数然后乘以 page size就可以得出要分配的空间size_t len (StackYellowPages StackRedPages) * os::vm_page_size();int allocate os::allocate_stack_guard_pages();// 通过create_stack_guard_pages函数从low_addr地址开始分配长度为len的区域底层是通过mmap系统调用完成的if (allocate !os::create_stack_guard_pages((char *) low_addr, len)) {warning(Attempt to allocate stack guard pages failed.);return; // 分配失败退出函数}// 通过系统调用mprotect设置这块区域不可访问也就是激活保护区if (os::guard_memory((char *) low_addr, len)) {_stack_guard_state stack_guard_enabled; // 设置激活保护区状态} else {// 激活失败就通过uncommit_memory释放空间warning(Attempt to protect stack guard pages failed.);if (os::uncommit_memory((char *) low_addr, len)) {warning(Attempt to deallocate stack guard pages failed.);}}
}