devopvoid / webrtc-java

WebRTC for desktop platforms running Java
Apache License 2.0
264 stars 62 forks source link

Leak of observer instances #146

Open kalaider opened 4 months ago

kalaider commented 4 months ago

Describe the bug webrtc-java 0.8.0. Callback instances (all XxxObservers passed to PeerConnectionFactory.createPeerConnection and such) are constantly leaking. In my case I need to create a large number of PCs in a long-running monitoring application which started to eat memory after migration from ice4j to webrtc-java. Heap dump analysis revealed that observers are kept alive by native code (GC Root: Global JNI).

To Reproduce Minimal reproducer:

package org.kalaider.webrtc;

import dev.onvoid.webrtc.PeerConnectionFactory;
import dev.onvoid.webrtc.PeerConnectionObserver;
import dev.onvoid.webrtc.RTCConfiguration;
import dev.onvoid.webrtc.RTCIceCandidate;
import dev.onvoid.webrtc.media.audio.AudioDeviceModule;
import dev.onvoid.webrtc.media.audio.AudioLayer;

import java.time.Duration;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class LeakTestJava {
    private static void createLeak() {
        var pcf = new PeerConnectionFactory(new AudioDeviceModule(AudioLayer.kDummyAudio));
        IntStream.range(0, 1000).forEach(i -> {
            pcf.createPeerConnection(new RTCConfiguration(), new PeerConnectionObserver() {
                private final String bigObject = IntStream.range(0, 1000).mapToObj(j -> "long-string").collect(Collectors.joining(" "));
                @Override public void onIceCandidate(RTCIceCandidate candidate) {
                    System.out.println(bigObject);
                }
            }).close();
        });
        pcf.dispose();
        System.out.println("leak created");
    }

    public static void main(String[] args) throws InterruptedException {
        createLeak();
        Thread.sleep(Duration.ofMinutes(10));
    }
}

After leak created message is printed, LeakTestJava$1 is in the top-1 by retained memory size.

Expected behavior Observers should not leak.

Desktop (please complete the following information):

Additional context One suspicious place where the leak is possible is JNI code that passes a pointer to rtc::RefCountedObjects to native webrtc APIs without releasing initial reference.