Why are commands executing out of order?

FG home at fgda.pl
Sat Feb 2 03:16:41 PST 2013


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){}
     }




More information about the Digitalmars-d-learn mailing list