Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: bb925e7440cc
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 9c91759c0543
Choose a head ref
  • 2 commits
  • 2 files changed
  • 2 contributors

Commits on Aug 6, 2015

  1. Fix an embedded runtime memory leak in Java7ClassValue

    Commit 09f15f9 enabled the
    Java7ClassValue implementation by default which exposed a runtime
    memory leak in the embedded use case. This fixes that leak by wrapping
    values stored in the java.lang.ClassValue instance with a
    WeakReference.
    bbrowning committed Aug 6, 2015
    Copy the full SHA
    0a1b66c View commit details

Commits on Aug 29, 2015

  1. Merge pull request #3228 from bbrowning/classvalue-runtime-leak

    Fix an embedded runtime memory leak in Java7ClassValue
    headius committed Aug 29, 2015
    Copy the full SHA
    9c91759 View commit details
Showing with 40 additions and 4 deletions.
  1. +22 −4 core/src/main/java/org/jruby/util/collections/Java7ClassValue.java
  2. +18 −0 spec/regression/embedded_runtime_leak_spec.rb
26 changes: 22 additions & 4 deletions core/src/main/java/org/jruby/util/collections/Java7ClassValue.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package org.jruby.util.collections;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;

/**
* A proxy cache that uses Java 7's ClassValue.
*/
@@ -10,13 +14,27 @@ public Java7ClassValue(ClassValueCalculator<T> calculator) {
}

public T get(Class cls) {
return proxy.get(cls);
// We don't check for null on the WeakReference since the
// value is strongly referenced by proxy's list
return proxy.get(cls).get();
}

private final java.lang.ClassValue<T> proxy = new java.lang.ClassValue<T>() {
// If we put any objects that reference an org.jruby.Ruby runtime
// (like RubyClass instances) in here we run into a circular
// reference situation that GC isn't handling where they will
// always be strongly referenced and never garbage collected. We
// break that by holding the computed values with a WeakReference.
private final java.lang.ClassValue<WeakReference<T>> proxy = new java.lang.ClassValue<WeakReference<T>>() {
// Strongly reference all computed values so they don't get
// garbage collected until this Java7ClassValue instance goes
// out of scope
private final List<T> values = new ArrayList<T>();

@Override
protected T computeValue(Class<?> type) {
return calculator.computeValue(type);
protected WeakReference<T> computeValue(Class<?> type) {
T value = calculator.computeValue(type);
values.add(value);
return new WeakReference(value);
}
};
}
18 changes: 18 additions & 0 deletions spec/regression/embedded_runtime_leak_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
describe "embedded runtimes" do
it "should not leak runtimes after tearing them down" do
num_runtimes = 10
mbean = java.lang.management.ManagementFactory.getMemoryMXBean
num_runtimes.times do
instance = org.jruby.Ruby.newInstance
instance.evalScriptlet <<-EOS
# eat up some memory in each runtime
$arr = 500000.times.map { |i| "foobarbaz\#{i}" }
EOS
instance.tearDown(false)
# Make sure GC can keep up
while mbean.getObjectPendingFinalizationCount > 0
sleep 0.2
end
end.should_not raise_error
end
end