Skip to content

Tamarin part III – Garbage Collector in Flash (10.0)

December 23, 2009

I did a lot of very processing intensive application during the last few years. Applications that required both CPU optimization and memory optimization. And I had a LOT of problem with the Garbage Collector of Flash. It was often holding the CPU for too long thus creating visible pause. That kind of behavior was of course unacceptable for real time application. I tried a lot of things in FlashIDE and FlexSDK to optimize what I could but most of that work was based on trial an error or misunderstanding of how GC really worked.

So I decided to take this one step further on my own time and read the whole Tamarin source.

When I first started thinking of this article, I had no idea what I was getting into.
During my first reading of Tamarin a few months ago, I saw some things about a Mark and Sweep Algorithm… Some ZCT algorithm and I thought everything was kind of trivial. No way!

*everything that I’m going to talk about is based on my own reading of the open-source framework Tamarin and public news from Adobe. I’m not representing Adobe in any way and if my interpretation is bad about anything, please tell me!*

As you know, Adobe as worked on bringing flash to portable device for some time now and obviously, memory management and performances of flash was kind of an issue for smaller device. In last march Lars Hansen did a GREAT review of what were the actual Issues of the GC and some actions that should be taken to fix theses.

I also started a discussion recently with Lars about the F10.1 GC . That GC is more focused on small device and less on application that require a LOT of memory. With some test I did the GC was going nuts and taking 1.6Go of memory with visible freeze of a few seconds. I’ll be filling a bug soon, but if F10.1 is released as the official player soon, a lot of games will fail!

By the way, If anyone have interesting management solution for memory consumed (allocated and freed) by visual assets created on the timeline. Please post your solutions!

But enough with this… Let’s start!

Tamarin GC is a mix of:

    1. Conservative collection with incremental Mark/Finalize/Sweep algorithm
    2. Deferred Reference Counting (DRC) with ZeroCountTable (ZCT)

 

Conservative collection with incremental Mark/Finalize/Sweep

This implies many things:

    1. Mark / Sweep: Every object in the system must have a “mark bit”
    2. Finalize: Object can have a destructor function called before being deleted
    3. Incremental: The Algorithm is processing over multiple frames.
    4. Conservative: The finalize/ sweep phase is scanning the whole Heap for object pointers

Marking:
When the Mark phase start, the garbage collector is aware of “roots”, which are starting points from which all “live” application data should be reachable. The collector starts scanning objects, starting at the roots and fanning outwards. For every object it encounters, it sets the mark bit.
The marking algorithm is incremental and can be processed over multiple frames. To do this the GC is using a “Mark Stack” of item to process and spend some time each frame marking the object in the stack. At the beginning all the GC roots are pushed onto the stack. Items on the stack (grey) are conservatively marked and unmarked (white) GC pointers discovered while processing each item are pushed on to the stack. When the stack is empty all the marking is complete.

//StartIncrementalMark() finishes any outstanding lazy sweeping and pushes all the roots onto the mark stack and calls IncrementalMark

 

StartIncrementalMarking()

		// FIXME (policy): arguably a bug to allow MarkItem to go recursive here without checking for
		// the time it takes.  Probably better just to push the roots and let IncrementalMark handle
		// the marking.

		{
			MMGC_LOCK(m_rootListLock);
			GCRoot *r = m_roots;
			while(r) {
				GCWorkItem item = r->GetWorkItem();
				if(item.ptr)
					MarkItem(item, m_incrementalWork);
				r = r->next;
			}
		}

 

//IncrementalMark() processes items on the mark stack until it's empty or until the time budget for the increment is exhausted. If the mark stack is empty on entry to IncrementalMark then it calls FinishIncrementalMark().

 

//FinishIncrementalMark marks from all the roots again, then creates a work item for the entire stack and marks that, and then calls Sweep

But what happens if an object is created and linked to another object that have already been marked (black). The logical answer would be: “the mark bit was not set so the object is available for garbage collection”. To handle this (bad) behavior, the GC is using what is called a “Write barrier”. The algorithm uses a tri-color flags with write barriers. Every object has 3 states: black, gray and white.

    1. Black means the object has been marked and is no longer in the work queue
    2. Gray means the object is in the work queue but not yet marked
    3. White means the object isn’t in the work queue and hasn’t been marked

The first increment will push all the roots on to the queue, thus after this step all the roots are gray and everything else is white. As the queue is processed all live objects go through two steps, from gray to black and white to gray. Whenever a pointer to a white object is written to a black object we have to intercept that write and remember to go back and put the white object in the work queue, that’s what a write barrier does.

Finalizing:
A finalizer is a method which will be invoked by the GC when an unreachable object is about to be destroyed.
In fact, Finalize() is called just before sweeping all objects. It can be considered as a sub-part of sweeping.
To be eligible for finalization, an object must inherits from GCFinalizedObject or RCFinalizedObject. For these objects, iIt’s similar to a (c++) destructor. It differs from a destructor in that it is usually called nondeterministically, i.e. in whatever random order the GC decides to destroy objects. C++ destructors are usually invoked in a comparatively predictable order, since they’re invoked explicitly by the application code. But since the sweeping processing does not traverse objects in a “logical” order it’s impossible to tell what object will be finalized first.

The finalization process examine the bit vector of every heap object to find dead objects, so it touches every block in the heap (even if only to retrieve the address of the bit vector).
Touching every block in the heap may be very slow and may result in visible pauses. Plus, each finalizer can take arbitrarily long to run, there can be lots of finalizers (every reference counted object is finalized), and every finalizable dead object is finalized at the end of the collection.

To experience that, you can create small app that play an animation. Add to the scene an array of 5 Million small strings or XML Node. If you let the animation play, there is a good chance you will see a visible pause in the animation. Even if you have no CPU intensive code, when the GC will be triggered and the finalization / Sweep will run, there will be a freeze.

		void GCAlloc::Finalize()
	{
		m_finalized = true;
		// Go through every item of every block.  Look for items
		// that are in use but not marked as reachable, and delete
		// them.

		GCBlock *next = NULL;
		for (GCBlock* b = m_firstBlock; b != NULL; b = next)

Sweeping:
In the Sweep phase, every object that wasn’t marked in the Mark phase is destroyed and its memory reclaimed. If an object didn’t have its mark bit set during the Mark phase, that means it wasn’t reachable from the roots anymore, and thus was not reachable from anywhere in the application code. But the algorithm is conservative; hence the collector assumes that every memory location might potentially contain a GC pointer.
That means that it might occasionally turn up a “false positive.” A false positive is a memory location that looks like it contains a pointer to a GC object, but it’s really just some JPEG image data or an integer variable or some other unrelated data. When the GC encounters a false positive, it has to assume that it MIGHT be a pointer since it doesn’t have an exact description of whether that memory is a pointer or not. So, the not-really-pointed-to object will be leaked. With a conservative GC, the leaks tend to be random, such that they don’t grow over time.

//Sweep() calls Finalize() and then sweeps any entirely empty pages

 

//Finalize() calls the Finalize method on all the allocators owned by the GC; this causes each to traverse its block list and run the finalizer of each unmarked finalizable object, and compute the number of live items per block. Blocks without live objects are added to lists that are processed by Sweep Non-empty pages are not swept during collection, but on demand as more memory is needed, and sometimes eagerly before a new collection starts. Since marking and sweeping are interleaved with mutator work, the main latency in the collection process comes in at the beginning, when StartIncrementalMark sweeps unswept pages, and at the end, when FinishIncrementalMark scans the stack and examines every page in the system and runs the finalizers for all objects that are going to be reclaimed (through GC::Finalize). 

 

Sweep()

		// ISSUE: this could be done lazily at the expense other GC's potentially expanding
		// unnecessarily, not sure its worth it as this should be pretty fast
		GCAlloc::GCBlock *b = smallEmptyPageList;
		while(b) {
			GCAlloc::GCBlock *next = b->next;
#ifdef _DEBUG
			b->alloc->SweepGuts(b);
#endif
			b->alloc->FreeChunk(b);

			sweepResults++;
			b = next;
		}		

 

Deferred Reference Counting (DRC)

Reference counting is a technique of keeping the number of references (pointers) to a an object. When a reference count get to zero, it’s safe to deallocate the object (which are no longer referenced). Classic Reference counting are hard to maintain and need explicit count management each time an object is linked/unlinked.

The main problem with RC is Circular References. If two object point to each other, they both have at least one reference and can never be collected! (One more reason to have the Mark/Sweep algorithm ready to clean everything up!)

Tamarin use Deferred Reference Counting (DRC) with Zero Count Table (ZCT)
In Deferred Reference Counting, a distinction is made between heap and stack references.
Stack references to objects tend to be very temporary in nature. Stack frames come and go very quickly. So, performance can be gained by not performing reference counting on the stack references.

Heap references are different since they can persist for long periods of time. So, in a DRC scheme, we continue to maintain reference counts in heap-based objects. So, reference counts are only maintained to heap-to-heap references.
We basically ignore the stack and registers. They are considered stack memory.
But since we ignore the stack, we can’t just delete an object when it’s reference count drop to zero! There could be (ignored) pointers in the stack to that object.

To deal with this, there is a mechanism called the Zero Count Table (ZCT).
When an object reaches zero reference count, it is not immediately destroyed; instead, it is put in the ZCT and when the ZCT is full, it is “reaped” to destroy some objects.
If an object is in the ZCT, it is known that there are no heap references to it. So, there can only be stack references to it. When reaped, the GC scans the stack to see if there are any stack references to ZCT objects. Any objects in the ZCT that are not found on the stack are deleted.

 

But when is the GC triggered?

The algorithm that triggers the GC collection (or Heap grow) is simple and is based on memory allocation since last collect and the fraction of the total heap it represent.

	 /* When an allocation fails because a suitable memory block is
	 * not available, the garbage collector decides either to garbage
	 * collect to free up space, or to expand the heap.  The heuristic
	 * used to make the decision to collect or expand is taken from the
	 * Boehm-Demers-Weiser (BDW) garbage collector and memory allocator.
	 * The BDW algorithm is (pseudo-code):
	 *
	 *    if (allocs since collect >= heap size / FSD)
	 *      collect
	 *    else
	 *      expand(request size + heap size / FSD)
	 *
	 * The FSD is the "Free Space Divisor."

The first thing to determine is when we decide to start marking. Now that we know when we start marking there are two conflicting goals to achieve in selecting the marking time slice:

    1. Maintain the frame rate
    2. Make sure the collector gets to the sweep stage soon enough to avoid too much heap expansion

If we don’t maintain the frame rate the movie will appear to pause and if we don’t mark fast enough the mutator could get ahread of the collector and allocate memory so fast that the collection never finishes and memory grows unbounded. The ideal solution will result in only one mark incremental per frame unless the mutator is allocating memory so fast we need to mark more aggressively to get to the sweep. So the frequency of the incremental marking will be based on two factors: the rate at which we can trace memory and the rate at which the mutator is requesting more memory.


void* GC::AllocBlock(int size, int pageType, bool zero)
{
GCAssert(size > 0);

// perform gc if heap expanded due to fixed memory allocations
if(!marking && !collecting && policy.queryStartCollectionAfterHeapExpansion())
{
if(incremental && !nogc)
StartIncrementalMark();
else
Collect();
}

 


bool GCPolicyManager::queryStartCollectionAfterHeapExpansion()
{
// this is the existing policy but it's not a good idea
return (blocksInHeapAfterPreviousAllocation > lowerLimitHeapBlocks() &&
blocksInHeapAfterPreviousAllocation < heap->GetTotalHeapSize() &&
querySufficientTimeSinceLastCollection());
}

 

//Issue: The intent of the free space divisor is not documented, as with too much else about MMgc. Given that block allocation updates both allocsSinceCollect and totalGCPages by the same amount when a block is allocated or freed, the test is that a>(t+a)/4, or a>t/3. I have no idea whether that was the intent, but I'm inclined to think not.

 

	uint64_t GCPolicyManager::zctNewReapThreshold(uint64_t zctSize, uint64_t zctOccupancy)
	{
		// how many objects trigger a reap, should be high
		// enough that the stack scan time is noise but low enough
		// so that objects to away in a timely manner

		const int ZCT_REAP_THRESHOLD = 512;

		uint64_t zctReapThreshold = zctOccupancy + ZCT_REAP_THRESHOLD;
		if(zctReapThreshold > zctSize * GCHeap::kBlockSize/sizeof(uintptr_t))
			zctReapThreshold = zctSize * GCHeap::kBlockSize/sizeof(uintptr_t);
		return zctReapThreshold;
	}

There is also the well known AS3 localConnection hack:


try {
new LocalConnection().connect('foo');
new LocalConnection().connect('foo');
} catch (e:*) {}
// the GC will perform a full mark/sweep on the second call.

So… How to use the flash GC?

But in general, since the GC is scanning the whole object range before sweeping (and finalize some objects like Strings, XML Nodes etc.) it’s best to keep a minimum heap size and object number.
If you have tens of thousands objects instantiated in your project, there is a good chance of having visible pause.
Preventing that can’t really be done with a “magic trick” and require a good engine architecture supporting optimized live object serialization to make the number of instance lower.
For instance, you can use AMF or your own serialization to write most object into a mapped ByteArray if they don’t require fast access.

But for many projects, the real problem is coming from assets created on the timeline (Flash IDE) because we have no control over theses. We can’t tell FlashIDE to “re-use” a sprite that is created a lot of time. We can’t make “real” object pooling with the timeline. And we have no information on rules determining memory allocation for these “timeline graphics” from Adobe. Using good tweening library could be a solution for some basic animations.

The GC of flash caused me a lot of problem in the past but it’s not because it’s bad. It’s just because we are doing very big application. Since we use a lot of visual object (sprites) in flash, there is often a LOT of memory added to the heap and the triggers are harder to manage because of the objects size.
For a game engine, having access to explicit collection could be great. But Adobe made a good call by making it conservative and hence accessible to a lot more people.

 

Interesting block of code:

	void GCHashtable::put(const void *key, const void *value)
	{
		GCAssert(table != NULL);
		int i = find(key, table, tableSize);
		if (!equals(table[i], key)) {
			// .75 load factor, note we don't take numDeleted into account
			// numValues includes numDeleted
			if(numValues * 8 >= tableSize * 3)
			{
				grow();
				// grow rehashes
				i = find(key, table, tableSize);
			}

void GCHashtable::grow()
	{
		int newTableSize = tableSize;

		unsigned int occupiedSlots = numValues - numDeleted;
		GCAssert(numValues >= numDeleted);

		// grow or shrink as appropriate:
		// if we're greater than %50 full grow
		// if we're less than %10 shrink
		// else stay the same

 

Sources and References:

Can take more?

Next post

Interpreting the future of Flash from the sources!

From → actionscript

8 Comments
  1. That was downright fascinating! I wonder: in your experience studying the GC and implementing real-time projects for it, what techniques would you recommend so as to avoid noticeable pauses due to GC? I’d especially be interested if the article was tailored to games, since you and I both develop Flash-based MMOs. In the meantime, I’ll keep reading these articles. Every one has been great! Keep up the good work!

    • I prefer to keep specific implementation from my job out of this blog. I’m sure you can understand why.
      But in general, since the GC is scanning the whole object range before sweeping plus doing finalization on certain objects (like String and XML Node etc.) it’s best to keep a minimum heap size and object number.
      If you have dozens of thousands objects instantiated in your project, there is a good chance of having visible pause.
      Preventing that can’t really be done with a “magic trick” and require a good engine architecture supporting optimized live object serialization to make the number of instance lower.
      For most project, the real problem is coming from assets created on the timeline because we have no control over theses. We can’t tell FlashIDE to “re-use” a sprite that is created a lot of time. We can’t make “real” object pooling with the timeline.
      I also forgot to conclude my post!
      The GC of flash caused me a lot of problem in the past but it’s not because it’s bad. It’s just because we are doing very big application. Since we use a lot of visual object (sprites) in flash, there is often a LOT of memory added to the heap and the triggers are harder to manage because of the objects size.
      For a game engine, having access to explicit collection can be great. But Adobe made a good call by making it conservative and hence accessible to a lot more people.

      • I understand wanting to keep specific implementation out of the blog. That’s been my policy too. I was asking for some general ideas… and you’ve provided them! Thanks again for the article and for the followup ideas and conclusion. It certainly gives me a lot to think about both architecturally and as far as day-to-day practices go.

  2. It’s indeed useful when you want to do “serious work” to understand the GC. But as you stated, there’s a whole unknown part of the Flash Player which is how the whole timeline and sprites are handled.

    For one of our game projects, we had to rewrite the whole timeline player in haXe and with some reuse optimizations we were able to get more performances than native implementation…

  3. Thanks on your marvelous posting! I quite enjoyed reading it, you can be a great author.

    I will always bookmark your blog and may come back sometime soon.
    I want to encourage continue your great posts, have a nice afternoon!

    I absolutely love your blog and find most of your post’s to be just what I’m looking for.
    Do you offer guest writers to write content to suit your needs?

    I wouldn’t mind producing a post or elaborating on some of the subjects you write about here. Again, awesome blog!
    My spouse and I stumbled over here different page and thought I should check things out. I like what I see so now i am following you. Look forward to going over your web page repeatedly.
    Everyone loves what you guys are usually up too. This kind of clever work and exposure! Keep up the superb works guys I’ve incorporated you guys to my own blogroll.

    Hello I am so delighted I found your webpage, I really found
    you by accident, while I was browsing on Yahoo for something else, Anyways I am here now and would just
    like to say thanks for a remarkable post and a all round entertaining
    blog (I also love the theme/design), I don’t have time to look over it all at the moment but I
    have saved it and also added your RSS feeds, so when I
    have time I will be back to read more, Please do keep up the excellent work.

    Admiring the hard work you put into your
    site and in depth information you present. It’s good to come across a blog every once in a while that isn’t the same old rehashed material.
    Wonderful read! I’ve saved your site and I’m adding your RSS feeds
    to my Google account.
    Hello! I’ve been following your web site for some time now and finally got the bravery to go ahead and give you a shout out from Humble Texas! Just wanted to tell you keep up the fantastic job!
    I’m really enjoying the theme/design of your blog.

    Do you ever run into any browser compatibility issues?
    A small number of my blog visitors have complained about my site not
    working correctly in Explorer but looks great in Opera.
    Do you have any recommendations to help fix this problem?

    I am curious to find out what blog system you have
    been using? I’m experiencing some minor security issues with my latest site and I would like to find something more safe. Do you have any solutions?
    Hmm it seems like your site ate my first comment (it was super long) so I guess I’ll just sum it up what I submitted and say, I’m thoroughly enjoying your blog. I too am an aspiring blog writer but I’m still new to everything.
    Do you have any tips and hints for inexperienced blog writers?
    I’d definitely appreciate it.
    Woah! I’m really digging the template/theme of this blog.
    It’s simple, yet effective. A lot of times it’s difficult to get that “perfect balance”
    between superb usability and appearance. I must say you have done
    a very good job with this. Also, the blog loads very quick for me on Safari.
    Outstanding Blog!
    Do you mind if I quote a few of your articles as
    long as I provide credit and sources back
    to your blog? My website is in the very same niche as yours and my users
    would genuinely benefit from some of the information you provide here.
    Please let me know if this okay with you. Regards!
    Hey there would you mind letting me know which webhost you’re using? I’ve loaded your blog
    in 3 different browsers and I must say this blog loads a lot faster then most.
    Can you suggest a good internet hosting provider at a honest price?
    Kudos, I appreciate it!
    Very good blog you have here but I was wanting to know if
    you knew of any forums that cover the same topics discussed here?
    I’d really love to be a part of online community where I can get opinions from other knowledgeable people that share the same interest. If you have any recommendations, please let me know. Many thanks!
    Hello there! This is my first comment here so I just wanted to give a quick shout out and say I truly enjoy reading through your blog posts. Can you suggest any other blogs/websites/forums that deal with the same subjects? Thanks for your time!
    Do you have a spam problem on this site; I also am a blogger, and I was curious about your situation; many of us have developed some nice methods and we are looking to exchange strategies with others, why not shoot me an email if interested.
    Please let me know if you’re looking for a writer for your weblog.
    You have some really good articles and I feel I would be
    a good asset. If you ever want to take some of the load off, I’d absolutely love to write some content for your blog in exchange for a link back to mine. Please blast me an e-mail if interested. Cheers!
    Have you ever considered about adding a little bit more than just your articles? I mean, what you say is valuable and all. But just imagine if you added some great pictures or videos to give your posts more, “pop”! Your content is excellent but with pics and clips, this blog could undeniably be one of the greatest in its niche. Superb blog!
    Fascinating blog! Is your theme custom made or did you download it from somewhere? A design like yours with a few simple tweeks would really make my blog jump out. Please let me know where you got your theme. Thanks a lot
    Hello would you mind sharing which blog platform you’re using?
    I’m going to start my own blog in the near future but I’m having a tough time deciding between BlogEngine/Wordpress/B2evolution and Drupal.
    The reason I ask is because your design and style seems different then most blogs and I’m looking for something completely unique. P.S My apologies for being off-topic but I had to ask!
    Hey just wanted to give you a quick heads up. The words in your article seem to be running off the screen in Chrome. I’m
    not sure if this is a format issue or something to do with browser compatibility but I figured I’d post to let you know. The design look great though! Hope you get the problem fixed soon. Thanks
    With havin so much content and articles do you ever run into any problems of plagorism or copyright infringement? My website has a lot of exclusive content I’ve either written myself or outsourced but it looks like a lot of it is popping it up all over the
    web without my permission. Do you know any techniques to help prevent content from being stolen?

    I’d truly appreciate it.
    Have you ever thought about creating an e-book or guest authoring on other blogs? I have a blog based on the same topics you discuss and would really like to have you share some stories/information. I know my visitors would enjoy your work. If you’re even
    remotely interested, feel free to send me an e-mail.

    Hey! Someone in my Myspace group shared this website with us so I came to check it out.

    I’m definitely loving the information. I’m bookmarking and will be tweeting this to my followers!
    Exceptional blog and wonderful style and design.

    Excellent blog! Do you have any suggestions for aspiring
    writers? I’m planning to start my own site soon but I’m a
    little lost on everything. Would you propose starting with a free platform like WordPress or go
    for a paid option? There are so many choices out
    there that I’m completely overwhelmed .. Any ideas? Thanks!
    My programmer is trying to convince me to move to .net from PHP. I have always disliked the idea because of the expenses. But he’s tryiong none the
    less. I’ve been using Movable-type on a number of websites for about a year and am anxious about switching to another platform. I have heard good things about blogengine.net. Is there a way I can import all my wordpress posts into it? Any kind of help would be really appreciated!
    Does your site have a contact page? I’m having a tough time locating it but, I’d like to send you an e-mail. I’ve got some creative ideas for your blog you might be interested in hearing.

    Either way, great website and I look forward to seeing it grow
    over time.
    It’s a shame you don’t have a donate button! I’d definitely donate to this superb blog! I guess for now i’ll settle for
    book-marking and adding your RSS feed to my Google account.
    I look forward to fresh updates and will talk about this website with my Facebook group.

    Talk soon!
    Greetings from Florida! I’m bored at work so I decided to browse your site on my iphone during lunch break. I really like the knowledge you present here and can’t wait to take a look when
    I get home. I’m surprised at how quick your blog loaded on my mobile .. I’m not even using WIFI, just 3G .
    . Anyways, awesome site!
    Hiya! I know this is kinda off topic however , I’d figured I’d ask.
    Would you be interested in exchanging links or maybe guest authoring a
    blog article or vice-versa? My blog goes
    over a lot of the same subjects as yours and I feel we could greatly benefit from each other.
    If you’re interested feel free to send me an e-mail. I look forward to hearing from you! Excellent blog by the way!
    Right now it sounds like WordPress is the top blogging platform out there right now. (from what I’ve read) Is that
    what you’re using on your blog?
    Fantastic post however I was wanting to know if you could write a litte more on this topic? I’d be very grateful if
    you could elaborate a little bit more. Thank you!

    Hello there! I know this is somewhat off topic but I
    was wondering if you knew where I could find a captcha plugin for my comment
    form? I’m using the same blog platform as yours and I’m having trouble finding one?
    Thanks a lot!
    When I originally commented I clicked the “Notify me when new comments are added” checkbox and now each time
    a comment is added I get three e-mails with the same comment.
    Is there any way you can remove me from that service?

    Appreciate it!
    Hello! This is my first visit to your blog! We are a collection of volunteers and starting a new initiative in a community in the
    same niche. Your blog provided us valuable information
    to work on. You have done a marvellous job!
    Good day! I know this is kinda off topic but I was wondering
    which blog platform are you using for this site? I’m getting fed up of WordPress because I’ve had problems with hackers and I’m looking at options for another platform. I would be great if you could point me in the direction of a good platform.
    Howdy! This post could not be written any better! Reading through this post reminds me of my previous room mate! He always kept chatting about this. I will forward this page to him. Fairly certain he will have a good read. Many thanks for sharing!
    Write more, thats all I have to say. Literally, it seems as though you relied on the video to make your point. You definitely know what youre talking about, why waste your intelligence on just posting videos to your blog when you could be giving us something informative to read?
    Today, I went to the beach with my children. I found a sea shell and gave it to my 4 year old daughter and said “You can hear the ocean if you put this to your ear.” She put the shell to her ear and screamed. There was a hermit crab inside and it pinched her ear. She never wants to go back! LoL I know this is completely off topic but I had to tell someone!
    Yesterday, while I was at work, my sister stole my iPad and tested to see if it can survive a forty foot drop, just so she can be a youtube sensation. My iPad is now broken and she has 83 views. I know this is totally off topic but I had to share it with someone!
    I was wondering if you ever thought of changing the page layout of your blog? Its very well written; I love what youve got to say. But maybe you could a little more in the way of content so people could connect with it better. Youve got an awful lot of text for only having one or 2 pictures. Maybe you could space it out better?
    Hi there, i read your blog from time to time and i own a similar one and i was just curious if you get a lot of spam feedback? If so how do you stop it, any plugin or anything you can suggest? I get so much lately it’s
    driving me crazy so any help is very much appreciated.

    This design is wicked! You certainly know how to keep a reader amused.
    Between your wit and your videos, I was almost moved to start my own blog (well, almost.
    ..HaHa!) Great job. I really enjoyed what you had to say, and more than
    that, how you presented it. Too cool!
    I’m truly enjoying the design and layout of your website. It’s a very easy on the eyes which makes it much more enjoyable
    for me to come here and visit more often. Did
    you hire out a developer to create your theme? Fantastic work!

    Hey! I could have sworn I’ve been to this website before but after reading through some of the post I realized it’s new to me.
    Anyhow, I’m definitely delighted I found it and I’ll be book-marking and checking back frequently!

    Hello! Would you mind if I share your blog with my facebook group?
    There’s a lot of people that I think would really enjoy your content. Please let me know. Thanks
    Hi, I think your site might be having browser compatibility issues. When I look at your blog site in Opera, it looks fine but when opening in Internet Explorer, it has some overlapping. I just wanted to give you a quick heads up! Other then that, awesome blog!
    Wonderful blog! I found it while surfing around on Yahoo News. Do you have any suggestions on how to get listed in Yahoo News? I’ve been
    trying for a while but I never seem to get there!
    Thanks
    Howdy! This is kind of off topic but I need some help from an established blog.
    Is it difficult to set up your own blog? I’m not very techincal but I can figure things out pretty fast. I’m thinking about setting up my own but I’m not sure where to start. Do you have any tips or suggestions? Cheers
    Hi! Quick question that’s completely off topic. Do you know how to make your site mobile friendly?

    My weblog looks weird when browsing from my
    iphone4. I’m trying to find a template or plugin that might be able to resolve this problem. If you have any recommendations, please share. Cheers!
    I’m not that much of a online reader to be honest but your sites really nice, keep it up! I’ll go ahead
    and bookmark your website to come back in the future. Cheers
    I really like your blog.. very nice colors & theme. Did you make this website yourself or did you hire someone to
    do it for you? Plz answer back as I’m looking to create my own blog and would like to know where u got this from. appreciate it
    Amazing! This blog looks exactly like my old one! It’s on a entirely different topic but it has pretty much the same page layout and design.
    Superb choice of colors!
    Hey just wanted to give you a brief heads up and let you know a few of the images aren’t loading correctly. I’m not sure why but I think its a linking issue.
    I’ve tried it in two different browsers and both show the same results.
    Hey are using WordPress for your blog platform? I’m new to the blog world but I’m trying to get started and set up my own. Do you require any html coding knowledge to make your own blog? Any help would be greatly appreciated!
    Hello this is kinda of off topic but I was wondering if blogs use WYSIWYG editors or if you have to manually code with HTML. I’m starting a blog soon but have no coding skills so I
    wanted to get guidance from someone with experience.
    Any help would be enormously appreciated!
    Hi! I just wanted to ask if you ever have any problems with hackers?
    My last blog (wordpress) was hacked and I
    ended up losing a few months of hard work due to no back up.
    Do you have any solutions to protect against hackers?
    Howdy! Do you use Twitter? I’d like to follow you if that would be ok. I’m absolutely enjoying your blog and look forward to new updates.

    Howdy! Do you know if they make any plugins to protect against hackers?
    I’m kinda paranoid about losing everything I’ve worked
    hard on. Any tips?
    Hey there! Do you know if they make any plugins to assist with SEO?
    I’m trying to get my blog to rank for some targeted keywords but I’m not seeing very good gains.
    If you know of any please share. Thank you!
    I know this if off topic but I’m looking into starting my own weblog and was wondering what all is required to get setup? I’m assuming
    having a blog like yours would cost a pretty penny? I’m not very web smart so I’m
    not 100% certain. Any tips or advice would be greatly appreciated.
    Many thanks
    Hmm is anyone else having problems with the images on this blog loading?

    I’m trying to find out if its a problem on my end or if it’s
    the blog. Any responses would be greatly appreciated.

    I’m not sure exactly why but this web site is loading extremely slow for me. Is anyone else having this issue or is it a problem on my end? I’ll check back later on and see if the
    problem still exists.
    Hey there! I’m at work browsing your blog from my new apple iphone! Just wanted to say I love reading through your blog and look forward to all your posts! Keep up the great work!
    Wow that was unusual. I just wrote an really long comment but after I clicked submit my comment didn’t appear.

    Grrrr… well I’m not writing all that over again. Regardless, just wanted to say wonderful blog!

Trackbacks & Pingbacks

  1. AS3 hidden treasure in the mm.cfg file. Revealing and documenting many Flash secrets! « jpauclair
  2. New Flash Visual Profiler « jpauclair
  3. mm.cfg Secrets « Michael.Huang's Blog

Comments are closed.