10
function f() {
  const w = new WeakMap();
  const o = {};

  w.set(o, { v: o });

  return w;
}

const weakMap = f();

For the given code, would the only weakMap item considered as reachable or not? Hence, will it be garbage collected or not?

PS: This question is asked from the perspective of the specification, not particular implementations.

zerkms
  • 230,357
  • 57
  • 408
  • 498
  • 1
    It's not supposed to. Things that only have circular references are eligible for garbage collection so should not stay in the weakMap. – jfriend00 Sep 21 '15 at 03:55
  • I was saying that it should get released because there are no external references to it and thus it is not reachable elsewhere. – jfriend00 Sep 21 '15 at 03:57
  • What about this example is circular? – loganfsmyth Sep 21 '15 at 03:58
  • @loganfsmyth the key and the value hold the same object. – zerkms Sep 21 '15 at 03:58
  • 1
    I see where you are coming from and the question itself is reasonable, but I don't think I'd personally categorize it as circular since `w` doesn't reference itself, and neither does `o`. – loganfsmyth Sep 21 '15 at 04:03
  • @loganfsmyth unless there is an official and the only correct definition for the "circular" term, yes, we can treat it differently :-) – zerkms Sep 21 '15 at 04:09
  • @loganfsmyth: But `o` does "reference" `{v: o}` (through `weakMap`) - that's all the weakmap is about :-) – Bergi Sep 21 '15 at 10:30
  • @Bergi Yeah I'm mostly being nit-picky, ignore me :P – loganfsmyth Sep 21 '15 at 17:02
  • @zerkms A circular reference would be more like `w = new WeakMap(); w2= new WeakMap(); w.set('a', w2); w2.set('a', w);`. The example you have in the question is more like a directed, acyclic graph. `w` references `o` and `{ v: o }`, and `{ v: o }` references `o`. – Ajedi32 Oct 22 '15 at 20:56
  • @Ajedi32 for me the `o -> { v: o } -> o` is pretty much a cycle reference. If you draw the objects graph you would see the clear loop. – zerkms Oct 22 '15 at 21:06
  • @zerkms But `o` isn't referencing anything. It's an empty object. – Ajedi32 Oct 22 '15 at 21:44
  • @Ajedi32 `o` references the `{ v: o }` object as a key of the map. If you draw the heap and stack variables and put the connections between them you will see the loop. – zerkms Oct 22 '15 at 21:56
  • @zerkms You mean a key of the WeakMap? Pretty sure that's actually the map referencing `{v: o}`, not `o` itself. `o` knows nothing about WeakMap or its keys. – Ajedi32 Oct 22 '15 at 22:44
  • @Ajedi32 map refers to the `{v: o}` through the `o`. Have you ever implemented a hash table (and yes, I understand that it does not have to be a hash table in this particular case)? Anyway, this dialogue is useless, I think it's a circular reference (and the standard authors apparently think so as well: they have put an explicit statement about this case in the standard). You don't think so. Okay. – zerkms Oct 22 '15 at 22:45
  • @zerkms Could you point to the place in the standard where it says that using the same object as both the key and value of a WeakMap forms a circular reference? That seems like a really strange thing to put in the ECMAscript standard, and the snippet in the answer below says nothing even remotely like that. I'm also pretty sure that hash table implementations don't normally involve dynamically adding properties to the objects used as their keys. Most implementations I've seen are, well... a table of hashes. Like this... https://goo.gl/dXp4nC – Ajedi32 Oct 22 '15 at 23:19
  • @zerkms Anyway, if you don't want to discuss this I'm happy to just drop it at this point. My initial motivation for bringing this up was to reword the question to be more technically accurate, but at this point it's starting to turn more into another case of ["someone is wrong on the internet"](https://xkcd.com/386/), which isn't particularly productive. – Ajedi32 Oct 22 '15 at 23:22
  • @Ajedi32 "Could you point to the place in the standard where it says that using the same object as both the key and value of a WeakMap forms a circular reference" --- I cannot, since they did not state that. But they explicitly explained this very case in the standard (see the answer), so they see this very case as an exception from any other case of using a `WeakMap` – zerkms Oct 22 '15 at 23:32
  • @Ajedi32 "Like this... goo.gl/dXp4nC" --- now have a look at the entry #152 with a collision. To resolve the hash collision you *must* store the initial key value. So - you first calculate a hash, find a bucket then iterate over a linked list comparing the **ACTUAL** key value (a reference to the object) with the key stored as the linked list element. So the hash table not only stores the hashes but the original keys as well (otherwise you would not be able to resolve collisions). – zerkms Oct 22 '15 at 23:34
  • @Ajedi32 which means that the linked list element contains both the data and the key and both of them refer to each other. – zerkms Oct 22 '15 at 23:36
  • @zerkms The statement below is basically just the definition of a WeakMap. It's what makes its behavior different from a regular Map. Without that statement in the standard, WeakMap would just be a regular Map that you can't iterate over. It's not particular to the scenario you mentioned. – Ajedi32 Oct 22 '15 at 23:41
  • 1
    @zerkms "So the hash table not only stores the hashes but the original keys as well" Yep, I agree. That's why I said "`w` references `o` and `{ v: o }`". It sounds like our disagreement is here: "which means that the linked list element contains both the data and the key **and both of them refer to each other**". What I'm saying is that the key and value do not refer to each other, the HashTable just refers to both of them. Neither of those objects contain references to each other. All references to those objects are within the HashTable itself. – Ajedi32 Oct 22 '15 at 23:45
  • 1
    Yep, now I see and now I agree that it's a DAG, not a cyclic graph. Not sure how to improve the subject though, since it's already put in quotes. – zerkms Oct 22 '15 at 23:45
  • @zerkms Yeah, I guess you're right. You can probably just leave it if you want. I didn't really intend to make such a big deal out of this, I just noticed a minor detail in the question that seemed wrong and felt like I needed to point it out. Just my detailed personality I guess... :-) As long as you understand where I'm coming from, I'm fine. – Ajedi32 Oct 23 '15 at 00:02
  • @Ajedi32 I do, I'm overly-pedantic sometimes as well. In this case I don't know how to change it so that it still was possible to explain the "problem" in a reasonable amount of words. There is also a chance someone one day will find it just because they have the same thoughts (and at first glance it looks circular) ;-) – zerkms Oct 23 '15 at 00:06

1 Answers1

12

Quoting WeakMap Objects section,

If an object that is being used as the key of a WeakMap key/value pair is only reachable by following a chain of references that start within that WeakMap, then that key/value pair is inaccessible and is automatically removed from the WeakMap.

In your case, the only way to reach o would be to start from one of the keys in the weakMap, as there is no external references to it. So, it would be considered as inaccessible.

WeakMap implementations must detect and remove such key/value pairs and any associated resources.

So, it would be eventually garbage collected.

thefourtheye
  • 206,604
  • 43
  • 412
  • 459