-
Notifications
You must be signed in to change notification settings - Fork 478
Expand file tree
/
Copy pathContextHolder.java
More file actions
55 lines (49 loc) · 2.62 KB
/
Copy pathContextHolder.java
File metadata and controls
55 lines (49 loc) · 2.62 KB
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
/*
* Copyright 2013-2026 chronicle.software; SPDX-License-Identifier: Apache-2.0
*/
package net.openhft.chronicle.hash.impl;
import net.openhft.chronicle.hash.impl.stage.hash.ChainingInterface;
/**
* A simple wrapper of {@link ChainingInterface}, the ChainingInterface field could be set to null.
* <h2>Motivation</h2>
* <p>{@link net.openhft.chronicle.map.ChronicleMap}'s context objects are huge and reference their
* own instances of key and value marshallers, which usually have buffers for serialization (e. g.
* see {@link net.openhft.chronicle.hash.serialization.impl.SerializableDataAccess}). The contexts
* are stored in {@link ThreadLocal}s, which are <i>instance</i> fields of ChronicleMap objects
* (see {@link net.openhft.chronicle.map.VanillaChronicleMap#cxt}). We want the context objects to
* be eligible for garbage collection as soon as possible after the ChronicleMap object is closed
* or becomes unreachable.
* <p>
* In JDK 8 ThreadLocals are implemented using {@link java.lang.ThreadLocal.ThreadLocalMap},
* a hash table with ThreadLocal objects themselves as the keys, weak-referenced. So after
* ChronicleMap (hence it's ThreadLocal cxt field) becomes unreachable, context objects should be
* eventually removed from ThreadLocalMap and become unreachable, but the current implementation
* does some cleanup of ThreadLocalMap lazily and only on ThreadLocal.set(), initialValue() and
* remove(), but not on the hot path of ThreadLocal.get(). I. e. if there is not enough "ThreadLocal
* activity" within a thread, stale ChronicleMap contexts may not be removed from ThreadLocalMaps
* forever, effectively this is a memory leak.
* <p>
* Moreover, if the user of the library closes ChronicleMap with close(), but has ChronicleMap
* object leaked, ChronicleMap's ThreadLocal field doesn't become unreachable and the leak of
* context objects is "legitimate".
* <p>
* Solution for this is to reference from {@link
* net.openhft.chronicle.map.VanillaChronicleMap#cxt} not huge context object directly, but small
* ContextHolder object, and clear the reference to context via {@link #clear()} on
* ChronicleMap.close() or from {@link sun.misc.Cleaner}'s registered cleaner for ChronicleMap, if
* it weren't closed, but becomes unreachable and reclaimed by the garbage collector.
*
* @see ChronicleHashResources#closeContext(ContextHolder)
*/
public final class ContextHolder {
private ChainingInterface context;
public ContextHolder(ChainingInterface context) {
this.context = context;
}
public ChainingInterface get() {
return context;
}
void clear() {
context = null;
}
}