summaryrefslogtreecommitdiff
path: root/runtime/gc/collector/immune_spaces.cc
blob: 28704af9197bda175d59fd2da4955da244a1a0cf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "immune_spaces.h"

#include <tuple>
#include <vector>

#include "base/logging.h"  // For VLOG.
#include "gc/space/space-inl.h"
#include "mirror/object.h"
#include "oat_file.h"

namespace art HIDDEN {
namespace gc {
namespace collector {

void ImmuneSpaces::Reset() {
  spaces_.clear();
  largest_immune_region_.Reset();
}

void ImmuneSpaces::CreateLargestImmuneRegion() {
  uintptr_t best_begin = 0u;
  uintptr_t best_end = 0u;
  uintptr_t best_heap_size = 0u;
  uintptr_t cur_begin = 0u;
  uintptr_t cur_end = 0u;
  uintptr_t cur_heap_size = 0u;
  using Interval = std::tuple</*start*/uintptr_t, /*end*/uintptr_t, /*is_heap*/bool>;
  std::vector<Interval> intervals;
  for (space::ContinuousSpace* space : GetSpaces()) {
    uintptr_t space_begin = reinterpret_cast<uintptr_t>(space->Begin());
    uintptr_t space_end = reinterpret_cast<uintptr_t>(space->Limit());
    if (space->IsImageSpace()) {
      // For the boot image, the boot oat file is always directly after. For app images it may not
      // be if the app image was mapped at a random address.
      space::ImageSpace* image_space = space->AsImageSpace();
      // Update the end to include the other non-heap sections.
      space_end = RoundUp(reinterpret_cast<uintptr_t>(image_space->GetImageEnd()),
                          kElfSegmentAlignment);
      // For the app image case, GetOatFileBegin is where the oat file was mapped during image
      // creation, the actual oat file could be somewhere else.
      const OatFile* const image_oat_file = image_space->GetOatFile();
      if (image_oat_file != nullptr) {
        intervals.push_back(Interval(reinterpret_cast<uintptr_t>(image_oat_file->Begin()),
                                     reinterpret_cast<uintptr_t>(image_oat_file->End()),
                                     /*image=*/false));
      }
    }
    intervals.push_back(Interval(space_begin, space_end, /*is_heap*/true));
  }
  std::sort(intervals.begin(), intervals.end());
  // Intervals are already sorted by begin, if a new interval begins at the end of the current
  // region then we append, otherwise we restart the current interval. To prevent starting an
  // interval on an oat file, ignore oat files that are not extending an existing interval.
  // If the total number of image bytes in the current interval is larger than the current best
  // one, then we set the best one to be the current one.
  for (const Interval& interval : intervals) {
    const uintptr_t begin = std::get<0>(interval);
    const uintptr_t end = std::get<1>(interval);
    const bool is_heap = std::get<2>(interval);
    VLOG(collector) << "Interval " << reinterpret_cast<const void*>(begin) << "-"
                    << reinterpret_cast<const void*>(end) << " is_heap=" << is_heap;
    DCHECK_GE(end, begin);
    DCHECK_GE(begin, cur_end);
    // New interval is not at the end of the current one, start a new interval if we are a heap
    // interval. Otherwise continue since we never start a new region with non image intervals.
    if (begin != cur_end) {
      if (!is_heap) {
        continue;
      }
      // Not extending, reset the region.
      cur_begin = begin;
      cur_heap_size = 0;
    }
    cur_end = end;
    if (is_heap) {
      // Only update if the total number of image bytes is greater than the current best one.
      // We don't want to count the oat file bytes since these contain no java objects.
      cur_heap_size += end - begin;
      if (cur_heap_size > best_heap_size) {
        best_begin = cur_begin;
        best_end = cur_end;
        best_heap_size = cur_heap_size;
      }
    }
  }
  largest_immune_region_.SetBegin(reinterpret_cast<mirror::Object*>(best_begin));
  largest_immune_region_.SetEnd(reinterpret_cast<mirror::Object*>(best_end));
  VLOG(collector) << "Immune region " << largest_immune_region_.Begin() << "-"
                  << largest_immune_region_.End();
}

void ImmuneSpaces::AddSpace(space::ContinuousSpace* space) {
  DCHECK(spaces_.find(space) == spaces_.end()) << *space;
  // Bind live to mark bitmap if necessary.
  if (space->GetLiveBitmap() != nullptr && !space->HasBoundBitmaps()) {
    CHECK(space->IsContinuousMemMapAllocSpace());
    space->AsContinuousMemMapAllocSpace()->BindLiveToMarkBitmap();
  }
  spaces_.insert(space);
  CreateLargestImmuneRegion();
}

bool ImmuneSpaces::CompareByBegin::operator()(space::ContinuousSpace* a, space::ContinuousSpace* b)
    const {
  return a->Begin() < b->Begin();
}

bool ImmuneSpaces::ContainsSpace(space::ContinuousSpace* space) const {
  return spaces_.find(space) != spaces_.end();
}

}  // namespace collector
}  // namespace gc
}  // namespace art