JDK-8012915 : ReservedSpace::align_reserved_region() broken on Windows
  • Type: Bug
  • Component: hotspot
  • Sub-Component: gc
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • OS: windows
  • Submitted: 2013-04-22
  • Updated: 2014-01-14
  • Resolved: 2013-04-26
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8 Other
8Fixed hs25Fixed
Related Reports
Relates :  
Description
The method ReservedSpace::align_reserved_region() does not work on Windows. It tries to free parts of the previously allocated memory by doing two calls to os::release_memory(). However, on Windows os::release_memory() is implemented as:

 VirtualFree(addr, 0, MEM_RELEASE)

which will always free up all the allocated memory:

http://msdn.microsoft.com/en-gb/library/windows/desktop/aa366892%28v=vs.85%29.aspx

"The function frees the entire region that is reserved in the initial allocation call to VirtualAlloc."

This means that if  ReservedSpace::align_reserved_region() is executed on Windows and we try to trim the beginning of the memory that we had allocated we will free all of the allocated memory. Subsequent calls to os::commit_memory() which will end up as:

VirtualAlloc(addr, bytes, MEM_COMMIT, PAGE_READWRITE)

will fail with 487, ERROR_INVALID_ADDRESS - Attempt to access invalid address.
Comments
I was able to write a unit test that reproduces the issue: // Test the manual alignment implementation. // First allocate a chunk of memory that has is unaligned for the large alignment that we want to use. // If the allocation happens on an unaligned address we release the memory and hope that the // subsequent allocation will re-use that address. If the address was aligned we hope that the // subsequent allocation will get an unaligned address size we used an unaligned size. // Then do the allocation with the large alignment. It is likely that this allocation // will trigger manual alignment since we most likely get an unaligned address. // Repeat this pattern three times to increase the likelihood that we get at least // one allocation with an unaligned address. void VirtualSpace::test_reserve_aligned() { size_t small_alignment = os::vm_allocation_granularity(); size_t small_size = small_alignment; size_t large_alignment = small_alignment * 4; size_t large_size = 2 * large_alignment; size_t large_unaligned_size = large_size * 2 + small_size; // First attempt ReservedSpace rs1(large_unaligned_size, small_alignment, false, false); intptr_t addr = (intptr_t)rs1.base(); if ((addr & (large_alignment - 1)) != 0) { rs1.release(); } ReservedSpace aligned_rs1(large_size, large_alignment, large_size, large_alignment, NULL); VirtualSpace vs1; assert(vs1.initialize(aligned_rs1, large_size), "allocation failed"); // Second attempt ReservedSpace rs2(large_unaligned_size, small_alignment, false, false); addr = (intptr_t)rs2.base(); if ((addr & (large_alignment - 1)) != 0) { rs2.release(); } ReservedSpace aligned_rs2(large_size, large_alignment, large_size, large_alignment, NULL); VirtualSpace vs2; assert(vs2.initialize(aligned_rs2, large_size), "allocation failed"); // Third attempt ReservedSpace rs3(large_unaligned_size, small_alignment, false, false); addr = (intptr_t)rs3.base(); if ((addr & (large_alignment - 1)) != 0) { rs3.release(); } ReservedSpace aligned_rs3(large_size, large_alignment, large_size, large_alignment, NULL); VirtualSpace vs3; assert(vs3.initialize(aligned_rs3, large_size), "allocation failed"); // Release memory aligned_rs1.release(); if (rs1.is_reserved()) { rs1.release(); } aligned_rs2.release(); if (rs2.is_reserved()) { rs2.release(); } aligned_rs3.release(); if (rs3.is_reserved()) { rs3.release(); } }
24-04-2013