java icon indicating copy to clipboard operation
java copied to clipboard

Memory leak in Cache indices when item is deleted

Open wuxudong opened this issue 1 year ago • 2 comments
trafficstars

Describe the bug

private void deleteFromIndices(ApiType oldObj, String key) {
    for (Map.Entry<String, Function<ApiType, List<String>>> indexEntry : this.indexers.entrySet()) {
      Function<ApiType, List<String>> indexFunc = indexEntry.getValue();
      List<String> indexValues = indexFunc.apply(oldObj);
      if (CollectionUtils.isEmpty(indexValues)) {
        continue;
      }

      Map<String, Set<String>> index = this.indices.get(indexEntry.getKey());
      if (index == null) {
        continue;
      }
      for (String indexValue : indexValues) {
        Set<String> indexSet = index.get(indexValue);
        if (indexSet != null) {
          indexSet.remove(key);
        }
      }
    }
  }

indexSet should also be deleted if it is empty; otherwise, a lot of untouchable HashSets will cause memory leaks.

The client-go fix is https://github.com/kubernetes/kubernetes/issues/84959

A proper fix would be:

private void deleteFromIndices(ApiType oldObj, String key) {
    for (Map.Entry<String, Function<ApiType, List<String>>> indexEntry : this.indexers.entrySet()) {
      Function<ApiType, List<String>> indexFunc = indexEntry.getValue();
      List<String> indexValues = indexFunc.apply(oldObj);
      if (CollectionUtils.isEmpty(indexValues)) {
        continue;
      }

      Map<String, Set<String>> index = this.indices.get(indexEntry.getKey());
      if (index == null) {
        continue;
      }
      for (String indexValue : indexValues) {
        Set<String> indexSet = index.get(indexValue);
        if (indexSet != null) {
          indexSet.remove(key);
          if (indexSet.isEmpty()) {
              index.remove(indexValue);
          }
        }
      }
    }
  }

Client Version 15.0.1

Kubernetes Version 1.19.3

Java Version Java 8

To Reproduce

Memory grows higher after items are created and removed.

Expected behavior

no memory leak after item is removed.

KubeConfig If applicable, add a KubeConfig file with secrets redacted.

Server (please complete the following information):

  • OS: [e.g. Linux]
  • Environment [e.g. container]
  • Cloud [e.g. Azure]

Additional context Add any other context about the problem here.

wuxudong avatar Jun 25 '24 02:06 wuxudong

Compare to client-go, in thread_safe_store.go

func (i *storeIndex) deleteKeyFromIndex(key, indexValue string, index Index) {
	set := index[indexValue]
	if set == nil {
		return
	}
	set.Delete(key)
	// If we don't delete the set when zero, indices with high cardinality
	// short lived resources can cause memory to increase over time from
	// unused empty sets. See `kubernetes/kubernetes/issues/84959`.
	if len(set) == 0 {
		delete(index, indexValue)
	}
}

wuxudong avatar Jun 25 '24 03:06 wuxudong

Makes sense, feel free to send a PR if you'd like. Otherwise we'll get to it eventually.

brendandburns avatar Jun 25 '24 04:06 brendandburns