Skip to content

zlib.*Sync methods fire asynchorous callbacks #1668

Closed

Description

@ChALkeR

https://github.com/iojs/io.js/blob/v2.0.1/lib/zlib.js#L458 — this line is called even for *Sync methods. That's not the only one.

See #1479 and #1665 (comment)

Activity

  1. ChALkeR commented on May 10, 2015

    @ChALkeR
    MemberAuthor
  2. added
    zlibIssues and PRs related to the zlib module and its compression dependencies.
    on May 10, 2015
  3. ChALkeR commented on May 10, 2015

    @ChALkeR
    MemberAuthor

    @Qard It's not the garbage collector that is broken as you supposed in #1665 (comment), it's zlib.*Sync methods not working as expected.

  4. ChALkeR commented on May 10, 2015

    @ChALkeR
    MemberAuthor

    That's since 07d3b21, I suppose.
    I might be wrong, I haven't tested that commit.
    @isaacs

  5. Qard commented on May 10, 2015

    @Qard
    Member

    I didn't say garbage collection was broken, I said your expectations of it were incorrect and that there needed to be documentation to explain that.

    In this case, the objects are not collectable simply because they are still accessible by future code--the close emitting function. That can be fixed.

    JavaScript in general is not a good language for sync looping though, as you need to trigger GC manually and hope that enough things are collectable to not rapidly run out of memory.

  6. trevnorris commented on May 10, 2015

    @trevnorris
    Contributor

    @ChALkeR Can you give me a code example where that manifests itself as a problem?

  7. ChALkeR commented on May 10, 2015

    @ChALkeR
    MemberAuthor

    @trevnorris I initially posted that to the issue: #1665 (comment) has the code sample, #1479 is the original report.

    @targos commented 20 days ago
    I was running a script to read sequentially a lot of gzipped files, and print on stdout the result of a computation for each file.
    After about 16'000 files, the process just stopped and Killed was printed on the terminal.

  8. trevnorris commented on May 10, 2015

    @trevnorris
    Contributor

    @ChALkeR Thanks. IMO it's a bug.

  9. ChALkeR commented on May 11, 2015

    @ChALkeR
    MemberAuthor

    @indutny On a side note, zlib.* methods (both sync and async) are collected only during full GC runs. Could something be done with that?
    Edit: It's Buffers fault: #1671.

  10. ChALkeR commented on May 17, 2015

    @ChALkeR
    MemberAuthor

    @bnoordhuis
    But the reason to defer the event is to prevent infinite recursion. I'm not sure if this is fixable without breaking something else.

    Is that the case for *Sync methods? Will it be safe not to defer the event for *Sync methods?

  11. bnoordhuis commented on May 17, 2015

    @bnoordhuis
    Member

    Is that the case for *Sync methods?

    Yes. Events always need to be asynchronous. The problem in a nutshell:

    // example 1
    function next() {
      var t = task();
      t.on('complete', next);
    }
    
    // example 2
    function next() {
      task(next);
    }

    In the first example, if 'complete' is synchronous, you don't have time to attach an event listener.

    In the second example, if the callback is synchronous, you get infinite recursion.

  12. ChALkeR commented on May 17, 2015

    @ChALkeR
    MemberAuthor

    @bnoordhuis But those events are not public in *Sync case and can't be used outside of the core code. I am not even sure if they are needed in the *Sync case.

  13. trevnorris commented on May 18, 2015

    @trevnorris
    Contributor

    @bnoordhuis just curious, is there ever a time where a synchronous task allows adding event listeners?

  14. piscisaureus commented on May 18, 2015

    @piscisaureus
    Contributor

    @bnoordhuis just curious, is there ever a time where a synchronous task allows adding event listeners?

    It happens in other places too (e.g. fs.createSyncReadStream(), process.stdout).
    It pretty much always causes problems, and I think it's a broken pattern that we shouldn't use.

  15. trevnorris commented on May 18, 2015

    @trevnorris
    Contributor

    @piscisaureus Sorry, I should have clarified the question. Is there ever a time where the public API allows attaching events to a synchronous task?

  16. 2 remaining items

  17. added
    memoryIssues and PRs related to Node.js memory management or memory footprint.
    on Aug 17, 2015
  18. Trott commented on Mar 15, 2016

    @Trott
    Member

    For the specific problem demonstrated with @ChALkeR's test code:

    'use strict';
    
    var zlib = require('zlib');
    var data = 'abcdefghijklmnopqrstuvwxyz';
    var gzipped = zlib.gzipSync(data);
    
    var time = process.hrtime();
    var count = 0, limit = 800000, block = 20000;
    
    function call() {
        var contents = zlib.gunzipSync(gzipped);
        count++;
        if (count % block === 0) {
            var t = process.hrtime(time);
            console.log(count + ': ' + block / (t[0] + t[1] / 1e9) + ' per second ' + JSON.stringify(process.memoryUsage()));
            time = process.hrtime();
        }
    }
    
    for (var i = 0; i < limit; i++) {
        call();
    }
    

    This appears to be fixed by just getting rid of the mechanism to emit close events altogether on the internal-ish Zlib object. It is not used internally and it is not documented. Still, that would probably be a semver-major move and perhaps an undesirable one? #5708

    Another option is to add an options object as a parameter to (again, internal-ish) Zlib.prototype.close() and set an option indicating that the thing is invoked by a *Sync() function (and thus no event should be queued). Effective but perhaps too inelegant? #5707

  19. Trott commented on Mar 17, 2016

    @Trott
    Member

    I believe #5707 is a fix for this. PTAL

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    memoryIssues and PRs related to Node.js memory management or memory footprint.zlibIssues and PRs related to the zlib module and its compression dependencies.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions