On 2013-02-02 07:49, Josh wrote:
But main's first writeln actually outputs after f.close().

Maybe because of output buffering and you need to add flush?

The program uses ~1GB of RAM overall, even though main.results is ~50MB
according to memSize.

Wrong comparison. You should have compared to the output file's size.
info.sizeof doesn't include the size of info.name.
In my test results were 30 MB but the output file was 101 MB.

Any attempts to call the GC do nothing, but I'm probably
doing it wrong though. Is it possible that I have a memory leak somewhere that
is causing this delay, or is this a DMD problem, or something else I haven't
even thought of?

It's a problem with array concatenation and memory fragmentation.
There are two ways out of this mess. First, there's the "Unix Way" - don't use the results array at all and print out info records immediately as they appear. Your program will use under 3 MB of RAM. :)

But if you really have to do some extra processing of results, then you can reduce the memory used like 6 times by using an Appender instead of concatenating arrays and by reserving a reasonable number of records, to limit possible initial fragmentation when the array is resized. My program used 145 MB whereas the output file was 101 MB. I think it's good enough. But that's scanning just one, non-system drive. Won't even try to scan them all.

Try it out:

    import std.datetime;
    import std.file;
    import std.stdio;
    import std.array;

    struct info
    {
        string name;
        bool isDir;
        ulong size;
        SysTime timeCreated;
        SysTime timeLastAccessed;
        SysTime timeLastModified;

        this(DirEntry d)
        {
            this.name = d.name;
            this.isDir = d.isDir;
            this.size = d.size;
            this.timeCreated = d.timeCreated;
            this.timeLastAccessed = d.timeLastAccessed;
            this.timeLastModified = d.timeLastModified;
        }
    }

    alias Appender!(info[]) InfoAppender;

    void main()
    {
        writeln("Scanning drives...");
        info[] results;
        InfoAppender app = appender(results);
        app.reserve(512*1024);  //
        for (char c = 'D'; c <= 'D'; c++)
        {
            if (exists(c ~ ":\\"))
            {
                app.put(info(DirEntry(c ~ ":\\")));
                scan(c ~ ":\\", app);
            }
        }
        File f = File("driveInfo.txt", "w");
        foreach (i; app.data)
        {
            f.writeln(i);
        }
        f.close();
        writeln(memSize(app.data));
    }

    void scan(string dir, ref InfoAppender app)
    {
        try
        {
            auto de = dirEntries(dir, SpanMode.shallow);
            foreach (d; de)
            {
                app.put(info(d));
                if (d.isDir())
                    scan(d.name, app);
            }
        }
        catch (FileException fe){}
    }

    size_t memSize(T)(T[] t)
    {
        return t.length * T.sizeof;
    }




And the preferred version to scan whole filesystem without wasting RAM:  :)


    import std.datetime;
    import std.file;
    import std.stdio;

    struct info
    {
        string name;
        bool isDir;
        ulong size;
        SysTime timeCreated;
        SysTime timeLastAccessed;
        SysTime timeLastModified;

        this(DirEntry d)
        {
            this.name = d.name;
            this.isDir = d.isDir;
            this.size = d.size;
            this.timeCreated = d.timeCreated;
            this.timeLastAccessed = d.timeLastAccessed;
            this.timeLastModified = d.timeLastModified;
        }
    }

    File f;

    void main()
    {
        writeln("Scanning drives...");
        f = File("driveInfo.txt", "w");
        for (char c = 'D'; c <= 'D'; c++)
        {
            if (exists(c ~ ":\\"))
            {
                f.writeln(info(DirEntry(c ~ ":\\")));
                scan(c ~ ":\\");
            }
        }
        f.close();
    }

    void scan(string dir)
    {
        try
        {
            auto de = dirEntries(dir, SpanMode.shallow);
            foreach (d; de)
            {
                f.writeln(info(d));
                if (d.isDir())
                    scan(d.name);
            }
        }
        catch (FileException fe){}
    }


Reply via email to