-
Notifications
You must be signed in to change notification settings - Fork 27
/
AllocateDirect.java
130 lines (112 loc) · 3.97 KB
/
AllocateDirect.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/*
* Copyright 2017, Yahoo! Inc. Licensed under the terms of the
* Apache License 2.0. See LICENSE file at the project root for terms.
*/
package com.yahoo.memory;
import static com.yahoo.memory.UnsafeUtil.unsafe;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.misc.Cleaner;
/**
* Provides access to direct (native) memory.
*
* @author Roman Leventov
* @author Lee Rhodes
*/
final class AllocateDirect implements AutoCloseable {
private static final Logger LOG = LoggerFactory.getLogger(AllocateDirect.class);
private final Deallocator deallocator;
private final Cleaner cleaner; //TODO-JDK9 import jdk.internal.ref.Cleaner;
private final long nativeBaseOffset;
/**
* Base Constructor for allocate native memory.
*
* <p>Allocates and provides access to capacityBytes directly in native (off-heap) memory
* leveraging the Memory interface.
* The allocated memory will be 8-byte aligned, but may not be page aligned.
* @param capacityBytes the the requested capacity of off-heap memory. Cannot be zero.
*/
AllocateDirect(final long capacityBytes) {
final boolean pageAligned = NioBits.isPageAligned();
final long pageSize = NioBits.pageSize();
final long allocationSize = capacityBytes + (pageAligned ? pageSize : 0);
NioBits.reserveMemory(allocationSize, capacityBytes);
final long nativeAddress;
try {
nativeAddress = unsafe.allocateMemory(allocationSize);
} catch (final OutOfMemoryError err) {
NioBits.unreserveMemory(allocationSize, capacityBytes);
throw err;
}
if (pageAligned && ((nativeAddress % pageSize) != 0)) {
//Round up to page boundary
nativeBaseOffset = (nativeAddress & ~(pageSize - 1L)) + pageSize;
} else {
nativeBaseOffset = nativeAddress;
}
deallocator = new Deallocator(nativeAddress, allocationSize, capacityBytes);
cleaner = Cleaner.create(this, deallocator);
}
@Override
public void close() {
doClose();
}
boolean doClose() {
try {
if (deallocator.deallocate(false)) {
// This Cleaner.clean() call effectively just removes the Cleaner from the internal linked
// list of all cleaners. It will delegate to Deallocator.deallocate() which will be a no-op
// because the valid state is already changed.
cleaner.clean();
return true;
} else {
return false;
}
} finally {
BaseState.reachabilityFence(this);
}
}
long getNativeBaseOffset() {
return nativeBaseOffset;
}
StepBoolean getValid() {
return deallocator.getValid();
}
private static final class Deallocator implements Runnable {
//This is the only place the actual native address is kept for use by unsafe.freeMemory();
private final long nativeAddress;
private final long allocationSize;
private final long capacity;
private final StepBoolean valid = new StepBoolean(true); //only place for this
private Deallocator(final long nativeAddress, final long allocationSize, final long capacity) {
BaseState.currentDirectMemoryAllocations_.incrementAndGet();
BaseState.currentDirectMemoryAllocated_.addAndGet(capacity);
this.nativeAddress = nativeAddress;
this.allocationSize = allocationSize;
this.capacity = capacity;
assert (nativeAddress != 0);
}
StepBoolean getValid() {
return valid;
}
@Override
public void run() {
deallocate(true);
}
boolean deallocate(final boolean calledFromCleaner) {
if (valid.change()) {
if (calledFromCleaner) {
// Warn about non-deterministic resource cleanup.
LOG.warn("A WritableDirectHandle was not closed manually");
}
unsafe.freeMemory(nativeAddress);
NioBits.unreserveMemory(allocationSize, capacity);
BaseState.currentDirectMemoryAllocations_.decrementAndGet();
BaseState.currentDirectMemoryAllocated_.addAndGet(-capacity);
return true;
} else {
return false;
}
}
}
}